Looping a texture on a surface - c++

I want to know how to loop a texture on the surface of an object.
For a practical example, I'm trying to handle rendering world geometry, so that when I resize a world object twice the size of its texture, the texture will then appear twice - not double in size.
Is there any proper way to handle this? The only thing I can think of would be to physically create a brand new texture which is of the right size and manually copied X amount of times, but that sounds like it would eat up a lot of memory really quickly.
Here's a picture showing what I'm looking for, when resizing a plane on the XAxis:
Along with many other variables, I pass an object's UVMap to my shader as the "texture coordinate", and then I perform the following for rendering an object's texture prior to the draw arrays call:
QImage image;
image = worldObject->getQImage(i); //Within a for loop, grabs the right texture if the object has differing textures per face of object
glBindTexture(GL_TEXTURE_2D, spot);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());

This is very easy to do. Where you currently use texture coordinates in the range [0.0, 1.0], you simply use a bigger range. For example, to repeat the texture twice, as shown in your example, you specify texture coordinates in the range [0.0, 2.0].
This works in combination with using GL_REPEAT for the texture wrap mode:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
These values are actually the default, so there's no need to set them if you did not set them to a different value earlier.
This specifies that the texture should be repeated for texture coordinates outside the [0.0, 1.0] range. For example, texture coordinates between 1.0 and 2.0 will be equivalent to the coordinates between 0.0 and 1.0, repeating the whole texture.

Related

GLSL Partially Overlapping Textures

I'm trying to blend two partially overlapping textures in GLSL and am wondering if I'm misunderstanding the concept of multi-texturing. Is it required that the textures fully overlap or can you have two offset textures that blend only where they overlap?
I have two images similar to the following (minus grid lines and text):
Example image
Ideally, the overlapping sections of the image would blend together nicely so that the final result would look like one smooth image that combines the two together. Overlapping orange pixels, for example, would blend together or take the higher intensity.
I'm new to GLSL and have been using this article GLSL Shader Article which uses a fragment shader to blend the textures (fairly standard).
Following the article, I#m setting up each texture like so:
glUseProgramObjectARB( m_hProgramObject );
GLint nParamObj = glGetUniformLocationARB( m_hProgramObject, pParamName_i );
...
glActiveTexture(GL_TEXTURE0 + nTextureID_i );
glBindTexture(GL_TEXTURE_2D, nTextureID_i);
glUniform1iARB( nParamObj, nTextureID_i );
I then bind each texture and draw triangle strips. My textures are created as:
glBindTexture( GL_TEXTURE_2D, m_nTextureID );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glTexImage2D(GL_TEXTURE_2D, 0, 4, nWidth, nHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, pbyData);
Does that process seem reasonable or am I misunderstanding the concept? Any tips or advice on how to achieve this?
That process certainly seems adequate. The advantage of using a fragment shader is you get complete control over how the textures are combined. For the offset, you may want two sets of texture coordinates - one for each image - or you could generate them implicitly. Figuring out what you want and writing the fragment shader will probably be the difficult bit. Unfortunately if you want to blend many different textures, the fragment shader used in this way can get quite expensive or just wont work with too many textures bound.
Your example image doesn't look like any blending has occurred at all - the images are just positioned over each other. In this case, it's easier just to draw separate bits of geometry with mapped textures.
Blending is typically done by the fixed pipeline blending stage. For example using the following calls...
glEnable(GL_BLEND)
glBlendFunc(src_scale, dest_scale)
One of the most common configuration is alpha blending with the over operator: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) in which the amount blended is given by the alpha value of the colour your drawing - possibly influenced by the A component in your GL_RGBA texture. You can further manipulate the blend equations if needed. See Blending.

opengl copying textures is skewing the textures

I'm copying a texture from a framebuffer to an empty texture using
float *temp = new float[width*height*4];
glBindTexture(GL_TEXTURE_2D, fbTex2);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, temp);
glBindTexture(GL_TEXTURE_2D, colour_map_tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, temp);
(yes I tried glCopyImageSubData() and it didn't work)
and colour_map_tex is initialized as
glGenTextures(1,&colour_map_tex);
glBindTexture(GL_TEXTURE_2D, colour_map_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);
this is then used to hold a colour map (everything drawn but using a single colour for each object/mesh) which is drawn to a frame buffer and then used to make a mask.
but the issue is when I use the mask, everything is aligned ie. the mask and the texture it is masking are lined up, but when I move the camera around the translations are slightly different which results in the masked image being really skewed in relation to the actual scene.
so my questions are, is there anything that is likely to be the cause of the skewing? or anything that can be done to fix it? would a 3rd frame buffer be a better idea instead of copying the data to an empty texture? and if so why?
overview of what is happening :
1. whole scene is being rendered with textures to a framebuffer.
2. whole scene is rendered a second time without textures but each mesh has a colour associated with it, this is rendered to a second framebuffer and is for a mask.
3. the mask texture is copied to an empty texture
4. the texture from the first frame buffer is drawn onto a plane the size of the viewport ( drawn to the second framebuffer)
5. the mask is overlayed onto the plane to mask out parts of the texture (drawn to the second view buffer)
6. the texture from the first frame buffer is drawn on to a plane the size of the viewport, this time drawn to the screen
7. there is an optional post processed image generated from the texture in the second frame buffer. which is semi transparent and drawn over the rendering of the scene.
I havent posted the whole display function because its pretty big but I'm happy to post more if there is a specific bit that you want.

texturing a glutSolidSphere

I need to add an earth texture to a glutSolidSphere. The problem is that I cannot figure out how to make the texture stretch over the entire sphere and still be able to rotate.
We're enabling the textures with.
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
glEnable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
//drawcode...
using GL_SPHERE_MAP in param instead of GL_OBJECT_LINEAR makes the textures look proper, but they cannot rotate.
The parameters I use for the texture are
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
I understand that GL_REPEAT tiles the texture, while using GL_CLAMP instead gives me the texture once on the object, but I cannot get it to stretch over the whole sphere.
Does anyone know how to properly texture a glutSolidSphere?
glutSolidSphere doesn't provide proper texture coordinates, and OpenGL built in texture generation allows only for linear mappings from vertex position to vertex texture coordinate, which essentially means that you can not use them to texture a 3-sphere with a 2-flat, bounded texture (for a mathematical explanation look up the topics of topology of manifolds and map theory).
So what can you do? There are a number of possible solutions:
Don't use glutSolidSphere, but some other geometry generator that does provide proper texture coordinates (though texturing a sphere with just a single bounded 2D texture is a difficult topic, there are several mappings, each with their problems)
Use a texture with the same topology as a sphere, a cube map, then you can use the GL_NORMAL_MAP for the texture gen mode, i.e.
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
Look up tutorials about cube mapping. But in a essence a cube map consists of 6 texture faces, arranged in a cube about the origin and texture coordinates are not points on the cube itself, but a direction from the origin and the addressed texel is the one, where the direction ray intersects with the cube.
Use a vertex shader, generating texture coordinates from vertex positions. Since a vertex shader is freely programmable, the mapping isn't required to be linear. Of course will run into the peculiarities of mapping a 3-sphere with a bounded 2-flat again.

Tiling a background in OpenGL

I'm sure this is a relatively simple question, it's just one thing I've always had trouble wrapping my mind around.
I have a 512x512 background I'd like to tile "infinitely." I've searched around and can't seem to find a whole lot, so I figured I'd come here. Anyway, here it is:
background http://dl.dropbox.com/u/5003139/hud/stars_far.png
So, there you have it. I have a ship sprite that can move anywhere on a 2D plane, and this is a top-down game. How would I render this background so that it covers every pixel of an arbitrarily sized window?
With GL_REPEAT texture clamping/wrapping mode, texture coordinates outside the range [0,1] will wrap around, repeating the texture. So you can draw a screen filling quad, but use larger texture coordinates. For example using the texture coordinates (0,0) to (10,10) will repeat the texture 10 times in each direction. Repeating mode is enabled for the currently bound 2D texture with
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

png image blurry when loaded onto texture

I have created a png image in photoshop with transparencies that I have loaded into and OpenGL program. I have binded it to a texture and in the program the picture looks blurry and I'm not sure why.
alt text http://img685.imageshack.us/img685/9130/upload2.png
alt text http://img695.imageshack.us/img695/2424/upload1e.png
Loading Code
// Texture loading object
nv::Image title;
// Return true on success
if(title.loadImageFromFile("test.png"))
{
glGenTextures(1, &titleTex);
glBindTexture(GL_TEXTURE_2D, titleTex);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, title.getInternalFormat(), title.getWidth(), title.getHeight(), 0, title.getFormat(), title.getType(), title.getLevel(0));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);
}
else
MessageBox(NULL, "Failed to load texture", "End of the world", MB_OK | MB_ICONINFORMATION);
Display Code
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, titleTex);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTranslatef(-800, 0, 0.0);
glColor3f(1,1,1);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2f(0,0);
glTexCoord2f(0.0, 1.0); glVertex2f(0,600);
glTexCoord2f(1.0, 1.0); glVertex2f(1600,600);
glTexCoord2f(1.0, 0.0); glVertex2f(1600,0);
glEnd();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
EDIT: I don't think i'm stretching each pixel should be two in the co-ordinate system
int width=800, height=600;
int left = -400-(width-400);
int right = 400+(width-400);
int top = 400+(height-400);
int bottom = -400-(height-400);
gluOrtho2D(left,right,bottom,top);
OpenGL will (normally) require that the texture itself have a size that's a power of 2, so what's (probably) happening is that your texture is being scaled to a size where the dimensions are a power of 2, then it's being scaled back to the original size -- in the process of being scaled twice, you're losing some quality.
You apparently just want to display your bitmap without any scaling, without wrapping it to the surface of another object, or anything like that (i.e., any of the things textures are intended for). That being the case, I'd just display it as a bitmap, not a texture (e.g. see glRasterPos2i and glBitmap).
Why would you want to use mipmapping and anisotropic filtering for a static image on your start screen in the first place? It looks unlikely the image will be rotated (what anisotropic filtering is for) or has to be resized many times really fast (what mipmapping is for).
If the texture is being stretched: try using GL_NEAREST for your GL_MAG_FILTER, in this case it could give better results (GL_LINEAR is more accurate, but has a nature of blurring).
If the texture is minimized: same thing, try using GL_NEAREST_MIPMAP_NEAREST, or even better, try using no mipmaps and GL_NEAREST (or GL_LINEAR, whichever gives you the best result).
I'd suggest that you make the png have a resolution in a power of 2's. Ie 1024x512 and place the part you want to drawn in the upper left corner of it still in the resolution for the screen. Then rescale the texcoords to be 800.0/1024.0 and 600.0/512.0 to get the right part from the texture. I belive that what is going on is glTexImage2D can sometime handle width and height that are not a power of 2 but can then scale the input image thus filter it.
An example of handling this can be viewed here (a iPhone - OpenGLES - project that grabs a screen part non-power of 2 and draws that into a 512x512 texture and rescales the GL_TEXTURE matrix, line 123, instead of doing a manual rescale of the texcoords)
Here is another post mentioning this method.
Here is an hypothesis:
Your window is 800x600 (and maybe your framebuffer too), but your client area is not, because of the window decoration on the sides.
So your frame-buffer gets resized when being blitted to the client area of your window. Can you check your window creation code ?
Beware of exact size of the client area of your window. Double check it is what you expect it to be
Beware of pixel alignment rules. You might need to add 0.5 to your x/y coordinates to hit the pixel centers. Description for DirectX can be found here - OpenGL rules may be different, though.