This article will cover the basics of texture mapping in OpenGL. This includes the uploading of the texture to the video memory and the application of the texture onto geometry. This article will not cover the actual loading of the texture data itself. That is left up to the reader. If you have prior experience in OpenGL texture mapping I suggest that you pass on reading this article unless you would like to refresh your memory. This document is aimed at the programmer who is trying to get started with OpenGL texture mapping. Snippets of code will be thrown in to clarify ideas and concepts.
So you have some raw RGB image data in a buffer and you want to apply it to your geometry in OpenGL? The first thing you have to do before OpenGL can use this raw texture data is upload it to the video memory. Once a texture is uploaded to the video memory it can be used throughout the time in which your application is running. Before a texture can be uploaded to the video memory there is some setup that must take place so OpenGL knows what to do with the image data that is passed to it. Below I will outline the order that certain calls need to be made in order to upload your texture. Note that these calls should be made once per texture when the application is started. Please check the pseudo code below for a better idea.
The first thing that must take place in the process of uploading the texture is a call to glBindTexture. What glBindTexture does is it tells OpenGL which texture "id" we will be working with. A texture "id" is just a number that you will use to access your textures. Here is a sample call.
This call will make texture that is associated with the ID of 13 the active texture. Any calls that have to do with OpenGL texture mapping will effect this texture. It is important that you remember this number since it will be needed again later on to actually apply the texture to geometry.
The glPixelStorei call tells OpenGL how the data that is going to be uploaded is aligned. A call to glPixelSrotei is shown below.
This call tells OpenGL that the pixel data which is going to be passed to it is aligned in byte order, this means that the data has one byte for each component, one for red, green and blue. Stick to the call above unless you have some sort of exotic data which I highly doubt. The alignment of data will probably change as you advance into OpenGL texture mapping.
The glTexParameteri sets the various parameters for the current OpenGL texture. The parameters that are passed and their effects on the texture are an advanced topic. If you would like to further research what each call does please take a look at the links provided at the end of this document. Each of these lines are important so make sure to get each in your application.
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);
Why did I leave out a description of what these do if they are so important? The properties that you can change with these calls are important to someone who would be more advanced. For someone who is just learning they should be seen as the "voodoo" that makes things work. Once you have a solid understanding of how texture mapping works in OpenGL then you should take a look at these properties.
The glTexEnvf call sets environment variables for the current texture. What this does is tell OpenGL how the texture will act when it is rendered into a scene. Below is a sample call which I use in my applications.
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
What this does is sets the active texture to GL_MODULATE. The GL_MODULATE attribute allows you to apply effects such as lighting and coloring to your texture. If you do not want lighting and coloring to effect your texture and you would like to display the texture unchanged when coloring is applied replace GL_MODULATE with GL_DECAL.
The glTexImage2D call is our goal. This call will upload the texture to the video memory where it will be ready for us to use in our programs. I am going to explain this call parameter by parameter since it is so important to what we are doing.
- target - The target of this call, it will always be GL_TEXTURE_2D.
- level - The level of detail number, this should be left at 0 for our purposes. Once you become more adept at OpenGL texture mapping this parameter will be something that you might change.
- internalformat - Internal components parameter. This tells OpenGL how many color components to represent internally from the texture that is uploaded. There are many symbolic constants for this parameter but the one which is most widely used is GL_RGB; this constant is equal to 3.
- width & height - The width and height of the image data. These must be integers that are equal to 2n+2(border) for some integer n. What this basically means is that the texture width and height must be a power of two (2,4,8,16,32,63,128,256,512, etc).
- border - Image border, must be 0 or 1. I always use 0 in my code since I do not use image borders.
- format - Format of the pixel data that will be uploaded. There are many constants which are accepted but GL_RGB is the value that is widely used.
- type - Type of data that will be uploaded. Again there are several symbolic constants but the one which I use is GL_UNSIGNED_BYTE.
- pixels - Pointer to the image data. This is the image data that will be uploaded to the video memory. Note that after your call to glTexImage2D you can free this memory since the texture is already uploaded into video memory.
Now that you know the parameters for glTexImage2D here is a sample call:
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, imageWidth, imageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, imageData);
That's all folks! After you have done everything above the texture will be uploaded and ready to be applied to your geometry. The next section will discuss the application of the texture to geometry. If this does not seem clear to you look at the links section at the end of this document for a texture mapping example.
Using the Texture
Well now that you have your texture uploaded you want to do something with it since its useless just sitting in memory. The process for applying a texture to geometry greatly depends on what type of data you are dealing with and how you would like things to run. Due to this fact in this section I will relay you some pointers on texture mapping, give an example of how to texture a quad and explain the texture coordinate system.
- Make sure that you have enabled texturing. You do this with the glEnable (GL_TEXTURE_2D) call.
- Make sure that you bind to a texture before you do any sort of glBegin/glEnd. You cannot bind to a texture in the middle of a begin/end pair.
- Make sure that you specify a texture coordinate before each vertex that makes up a face. If you have 3 vertices the pattern for texture mapping the triangle would go like this: TexCoord; VertexCoord; TexCoord; VertexCoord; TexCoord; VertexCoord;
- Make sure that you store your texture id's in variables, it makes things easier.
- Make use of glGenTextures. Its the easy way to get a free texture id.
A Textured Quad
Below is an example of how you would texture a quad. This code assumes that texturing has been enabled and that there has been a texture uploaded with the id of 13.
glBindTexture (GL_TEXTURE_2D, 13);
glTexCoord2f (0.0, 0.0);
glVertex3f (0.0, 0.0, 0.0);
glTexCoord2f (1.0, 0.0);
glVertex3f (10.0, 0.0, 0.0);
glTexCoord2f (1.0, 1.0);
glVertex3f (10.0, 10.0, 0.0);
glTexCoord2f (0.0, 1.0);
glVertex3f (0.0, 10.0, 0.0);
The Texture Coordinate System
The image above shows the OpenGL texture coordinate system. In the code above the calls to glTexCoord2f are very important as to what the end result of the texture mapping will be. When you make a call to glTexCoord2f (x,y) OpenGL places the texture coordinate at that place on the image. If you are texturing a triangle there will be three texture coords on the image. Once a glEnd is reached the triangle which is formed by the texture coordinates is then mapped onto the triangle that is made up from the vertices.