OpenGL:Tutorials:Tutorial Framework:Texture Mapping
Texture mapping is the application of an image to a polygon, this gives the illusion of detail without pushing up the poly count.
Contents |
Loading the Texture
For this tutorial I have used our own TGA loader as the image loader. The code was simply cut and pasted into 'tga.h'.
You can use any method to load an image as long as you know five things:
- A pointer to the image data,
- The image width,
- The image height,
- The color depth,
- The format of the image data,
I'm going to bundle up the texture loading into LoadTexture(), this function takes and filename and returns a GLuint texture handle.
OpenGL uses it's own GLuint (unsigned integer) datatype as a handle to reference textures once they are loaded. In this example we have two texture handles:
GLuint TexID1,TexID2; // Handles to our textures
This could easily be an array or a struct of your own definition.
The texture handle must be initalised before use:
glGenTextures(1,&Texture); // Allocate space for texture
glGenTextures() generates the texture handle in the second parameter, you can generate multiple handles by specifying the quantity in the first parameter and an array in the second.
Once we have our handle, we can bind to it:
glBindTexture(GL_TEXTURE_2D,Texture); // Set our Tex handle as current
This means that all subsequent texture operations will use the specified texture.
Now we pass our image to OpenGL to produce the texture:
glTexImage2D(GL_TEXTURE_2D,0,3,Img.GetWidth(),Img.GetHeight(),0,GL_RGB,GL_UNSIGNED_BYTE,Img.GetImg());
The TGA image class is providing most of the information here, the width, height, img pointer as discussed above.
This call is for a 24-bit texture, the 3rd ,7th and 8th parameters specify the image format. See the source for 32-bit image parameters.
The second parameter is the mip map level, 0 will do for now, I'll cover mip maps another time.
Now our image has been passed to OpenGL, we can discard our copy, OpenGL will manage the image until we call glDeleteTextures() to remove it. However, there are a few more things that we must do before we can use the texture:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
glTexParameter() is another function that comes in a few flavours. Some versions accept float values or arrays as arguments. Here we just need to specify a filter to use on our texture when it is scaled. The most common filters are GL_NEAREST and GL_LINEAR. GL_LINEAR produces the best results, but GL_NEAREST is faster. We also specify texture wrapping behaviour here, GL_REPEAT means that texture coordinates outside the range 0.0 - 1.0 will produce duplicates of the texture, while GL_CLAMP stops any wrapping from occuring.
Now our texture is ready for use.
Applying the Texture
Applying the texture to a polygon is achieved by specifying texture coordinates alongside the vertices.
First we have to enable texture mapping:
glEnable(GL_TEXTURE_2D);
We also have to tell OpenGL which texture to use:
glBindTexture(GL_TEXTURE_2D,TexID1);
The command glTexCoord() is used to specify the texture coordinates. It's another multi-flavour GL function, here we're using the float version:
glBegin(GL_QUADS); glTexCoord2f(1.0f,1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f,0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f,0.0f); glVertex3f( 1.0f, 1.0f,-1.0f); glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f, 1.0f,-1.0f); glEnd();
Again, the range of the texture coords is 0.0 - 1.0. This seems weird when the obvious measure for image maps is pixels. However, this system means that we can change the texture size and still use the same mapping coords to produce the same result. An easy way to calculate these coords is (Pixel X Pos / Image Width) and (Pixel Y Pos / Image Height). Remember that the behaviour or texture coords outside the range 0.0 - 1.0 will be defined by the TexParameter settings.
Press 't' during the demo to see the texture mapped using partial sections around the side faces of the cube.
Finally, we delete the textures to clean up:
glDeleteTextures(1,&TexID1); glDeleteTextures(1,&TexID2);
Source Code
The source to Render.cpp, compile this demo using the OpenGL Tutorial Framework.
#include "Framework.h" #include "tga.h" GLuint LoadTexture(char *TexName); void Render(void) { GLuint TexID1,TexID2; // Handles to our textures float Rotate=0.0f; // A rotation value to be used to spin our polygon glClearColor(0,0,0,0); // Setup our screen glViewport(0,0,800,600); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f,800.0f/600.0f,1.0f,500.0f); glMatrixMode(GL_MODELVIEW); // Ensure correct display of polygons glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); // Load the textures TexID1=LoadTexture("Logo.tga"); TexID2=LoadTexture("Logo2.tga"); // This loop will run until Esc is pressed while(RunLevel) { if(Keys[VK_ESCAPE]) // Esc Key RunLevel=0; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); // Reset current matrix (Modelview) // Do our rotations glTranslatef(0.0f,0.0f,-5.0f); glRotatef(Rotate,0.0f,0.0f,1.0f); glRotatef(Rotate,1.0f,0.6f,0.0f); // Enable texturing and select first texture glColor3f(1.0f,1.0f,1.0f); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,TexID1); // Draw the top face glBegin(GL_QUADS); glTexCoord2f(1.0f,1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f,0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f,0.0f); glVertex3f( 1.0f, 1.0f,-1.0f); glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f, 1.0f,-1.0f); glEnd(); // Select second texture glBindTexture(GL_TEXTURE_2D,TexID2); glBegin(GL_QUADS); glTexCoord2f(1.0f,0.0f); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f,-1.0f,-1.0f); glTexCoord2f(0.0f,1.0f); glVertex3f( 1.0f,-1.0f,-1.0f); glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f,-1.0f, 1.0f); glEnd(); // Press 't' to texture the side faces if(Keys['T']) { glEnable(GL_TEXTURE_2D); // Draw textured side faces glBegin(GL_TRIANGLE_STRIP); glTexCoord2f(1.0f,0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2f(1.0f,0.3f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f,0.3f); glVertex3f( 1.0f,-1.0f, 1.0f); glTexCoord2f(1.0f,0.5f); glVertex3f( 1.0f, 1.0f,-1.0f); glTexCoord2f(0.0f,0.5f); glVertex3f( 1.0f,-1.0f,-1.0f); glTexCoord2f(1.0f,0.75f); glVertex3f(-1.0f, 1.0f,-1.0f); glTexCoord2f(0.0f,0.75f); glVertex3f(-1.0f,-1.0f,-1.0f); glTexCoord2f(1.0f,0.95f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f,0.95f); glVertex3f(-1.0f,-1.0f, 1.0f); glEnd(); } else { glDisable(GL_TEXTURE_2D); // Draw colored side faces glBegin(GL_TRIANGLE_STRIP); glColor3f(0.8f,0.8f,0.8f); // Gray glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f(-1.0f,-1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glColor3f(0.0f,1.0f,0.0f); // Green glVertex3f( 1.0f,-1.0f, 1.0f); glColor3f(1.0f,1.0f,0.0f); // Yellow glVertex3f( 1.0f, 1.0f,-1.0f); glColor3f(0.0f,1.0f,1.0f); // Aqua? glVertex3f( 1.0f,-1.0f,-1.0f); glColor3f(0.6f,0.6f,0.6f); // Gray glVertex3f(-1.0f, 1.0f,-1.0f); glColor3f(0.1f,0.1f,0.1f); // Dark Gray glVertex3f(-1.0f,-1.0f,-1.0f); glColor3f(0.0f,0.0f,1.0f); // Blue glVertex3f(-1.0f, 1.0f, 1.0f); glColor3f(1.0f,0.0f,1.0f); // Red glVertex3f(-1.0f,-1.0f, 1.0f); glEnd(); } // Add to the rotation for next frame Rotate+=0.05f; // Show our cube FlipBuffers(); } // Clean up glDeleteTextures(1,&TexID1); glDeleteTextures(1,&TexID2); } GLuint LoadTexture(char *TexName) { TGAImg Img; // Image loader GLuint Texture; // Load our Texture if(Img.Load(TexName)!=IMG_OK) return -1; glGenTextures(1,&Texture); // Allocate space for texture glBindTexture(GL_TEXTURE_2D,Texture); // Set our Tex handle as current // Create the texture if(Img.GetBPP()==24) glTexImage2D(GL_TEXTURE_2D,0,3,Img.GetWidth(),Img.GetHeight(),0, GL_RGB,GL_UNSIGNED_BYTE,Img.GetImg()); else if(Img.GetBPP()==32) glTexImage2D(GL_TEXTURE_2D,0,4,Img.GetWidth(),Img.GetHeight(),0, GL_RGBA,GL_UNSIGNED_BYTE,Img.GetImg()); else return -1; // Specify filtering and edge actions glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); return Texture; }
Downloads
OpenGL_Tut3_(TexMap).zip - A zip including all source code, image files and Win32 exe.
