Advanced OpenGL Texture Mapping by (03 April 2000) | Return to The Archives

Introduction

As we all know texture mapping is a crucial element in today's games and graphic oriented programs, without texture mapping the worlds and models that are rendered would be far from aesthetically pleasing. This article will focus on the advanced features of OpenGL texture mapping and how they can be used to modify the way in which textures are rendered. With OpenGL's texture mapping features you can control the way in which your texture is stored internally, how it is filtered and how it is wrapped when applied to an object. These features can determine how fast your application will run as well as its visual quality. This is by no means a how to article on OpenGL texture mapping, I assume the reader has a grasp of texture mapping and is looking for more advanced topics. If you are looking for an introductory article please see OpenGL Texture Mapping : An Introduction. The first topic I will cover is OpenGL's mipmapping features.

Mipmapping

When a scene is rendered in OpenGL textured objects are drawn at varying distances from the viewpoint, some close and some distant. As a textured object moves away from the viewer the texture must be filtered down so it can be applied to the smaller object. The problem that arises from filtering the texture down is that as objects move further away from the viewpoint the texture map may flicker due to the filtering. The solution to this annoying problem is mipmapping. Mipmapping is the process in which a set of filtered texture maps of decreasing resolution are generated from a single high resolution texture and used to improve accuracy during texture mapping. Each individual mipmap is a distinct texture, it may look like the original, but it is a downsized and filtered version of the pervious mipmap level. Mipmapping allows OpenGL to apply the appropriate level of detail for a texture when rendering rather than shrinking the original texture.
Generating And Using Mipmaps
Each mipmap level is generated by taking half the size of the previous mipmap and then applying some sort of filter to it. If we have a base image that is 64x64 in size, the lower levels of detail will be 32x32, 16x16, 8x8, 4x4, 2x2 and 1x1. There are two ways to calculate the mipmaps and use them in OpenGL, by hand or through the gluBuild2DMipmaps() function. If mipmaps are generated using your own algorithm, the glTexImage2D() function would be used with an increasing level parameter for each successive level of detail, with level 0 being the base texture level. More often than not, the gluBuild2DMipmaps() utility function will be used to generate a set of mipmaps for a given texture. gluBuild2DMipmaps() will take care of filtering and uploading the mipmaps to memory. The gluBuild2DMipmaps() utility function is the same as glTexImage2D(), except for the fact that it builds mipmaps.
Now that the different levels of detail have been generated how can they be used to improve the quality of a textured object? Once the mipmaps have been calculated for a texture and uploaded into memory no special code is needed to use them. OpenGL will automatically select the best level of detail to use for the texture without any intervention from the programmer. Which mipmap is selected can be defined with the glTexParameter() function, described in the next section. The tradeoff with mipmaps is that they will require additional texture memory and some extra computation must be made to generate them.

No mipmapping | Mipmapping

Notice how the texture is distorted in the distance without mipmaps, but with mipmaps the texture is smooth and does not become distorted in the distance.

glTexParameter

The glTexParameter() function is a crucial part of OpenGL texture mapping, this function determines the behavior and appearance of textures when they are rendered. Below is a summary of the various parameters and what their effect is on the final rendered texture. Take note that each texture uploaded can have its own separate properties, texture properties are not global. One texture could clamp is texture coordinates while another wraps them, the properties of one texture will not effect others.

Target | Specifies the target texture
GL_TEXTURE_1D | One dimensional texturing.
GL_TEXTURE_2D | Two dimensional texturing.

Texture Parameter | Accepted values | Description
GL_TEXTURE_MIN_FILTER | GL_NEAREST , GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR and GL_LINEAR_MIPMAP_LINEAR | The texture minification function is used when a single screen pixel maps to more than one texel, this means the texture must be shrunk in size. Default setting is GL_NEAREST_MIPMAP_LINEAR.
GL_TEXTURE_MAG_FILTER | GL_NEAREST or GL_LINEAR | The texture magnification function is used when the pixel being textured maps to an area less than or equal to one texel, this means the texture must be magnified. Default setting is GL_LINEAR.
GL_TEXTURE_WRAP_S | GL_CLAMP or GL_REPEAT | Sets the wrap parameter for the s texture coordinate. Can be set to either GL_CLAMP or GL_REPEAT. Default setting is GL_REPEAT.
GL_TEXTURE_WRAP_T | GL_CLAMP or GL_REPEAT | Sets the wrap parameter for the t texture coordinate. Can be set to either GL_CLAMP or GL_REPEAT. Default setting is GL_REPEAT.
GL_TEXTURE_BORDER_COLOR | Any four values in the [0, 1] range | Sets the border color for the texture, if border is present. Default setting is (0, 0, 0, 0).
GL_TEXTURE_PRIORITY | [0, 1] | Specifies the residence priority of the texture, use to prevent OpenGL from swapping textures out of video memory. Can be set to values in the [0, 1] range. See glPrioritizeTextures() for more information or this article on Gamasutra.

Parameter | Description
GL_CLAMP | Clamps the texture coordinate in the [0,1] range.
GL_REPEAT | Ignores the integer portion of the texture coordinate, only the fractional part is used, which creates a repeating pattern. A texture coordinate of 3.0 would cause the texture to tile 3 times when rendered.
GL_NEAREST | Returns the value of the texture element that is nearest (in Manhattan distance) to the center of the pixel being textured. Use this parameter if you would like your texture to appear sharp when rendered.
GL_LINEAR | Returns the weighted average of the four texture elements that are closest to the center of the pixel being textured. These can include border texture elements, depending on the values of GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T, and on the exact mapping. Use this parameter if you would like your texture to appear blurred when rendered.
GL_NEAREST_MIPMAP_NEAREST | Chooses the mipmap that most closely matches the size of the pixel being textured and uses the GL_NEAREST criterion (the texture element nearest to the center of the pixel) to produce a texture value.
GL_LINEAR_MIPMAP_NEAREST | Chooses the mipmap that most closely matches the size of the pixel being textured and uses the GL_LINEAR criterion (a weighted average of the four texture elements that are closest to the center of the pixel) to produce a texture value.
GL_NEAREST_MIPMAP_LINEAR | Chooses the two mipmaps that most closely match the size of the pixel being textured and uses the GL_NEAREST criterion (the texture element nearest to the center of the pixel) to produce a texture value from each mipmap. The final texture value is a weighted average of those two values.
GL_LINEAR_MIPMAP_LINEAR | Chooses the two mipmaps that most closely match the size of the pixel being textured and uses the GL_LINEAR criterion (a weighted average of the four texture elements that are closest to the center of the pixel) to produce a texture value from each mipmap. The final texture value is a weighted average of those two values.

Examples
Min / Max Filter : GL_NEAREST | Min / Max Filter : GL_LINEAR
Wrap S : GL_CLAMP Wrap T : GL_CLAMP | Wrap S : GL_CLAMP Wrap T : GL_REPEAT
Wrap S : GL_REPEAT Wrap T : GL_CLAMP | Wrap S : GL_REPEAT Wrap T : GL_REPEAT

Texture Internal Formats

Texture internal formats were introduced in OpenGL 1.1 and provide a means to regulate how textures look when rendered, how fast the texture is rendered and how much memory the texture will take up. Care must be taken in regard to the third parameter of glTexImage2D(), which is internalformat, to take advantage of the texture internal formats. For a list of all texture internal formats take a look at this table, which provides information regarding each format. This table was reproduced from the SIGGRAPH '99 Advanced Graphics Programming Techniques Using OpenGL course notes.
Usage
The big question now is, how can this information be used in an application? If a texture is known to contain gray-scale or luminance values only then the GL_LUMINANCE format should be used rather than GL_RGB. If a small memory footprint and better performance is desired, then the GL_RGB4 format should be used. Using GL_RGB4 sacrifices texture quality for speed and low memory usage. If high visual quality is needed then the GL_RGB8 format could be used at the expense of speed and memory usage.

What is the catch for specifying the texture internal format? There is none. If the requested format is not supported by the implementation of OpenGL, the closest supported format will be selected for the texture. If a generic internal format is specified, GL_RGB for example, OpenGL will pick the most appropriate format to use for the particular implementation. Not all OpenGL implementations support all formats listed in the table. If GL_RGB8 is requested, there is no guarantee that the texture data will be stored in this manner. The internal texture format parameter is merely a hint for the implementation, if the requested format is supported it will be used, but if it is not supported the closest supported format will be used.
A final note is that the internalformat parameter is independent of the format parameter in the glTexImage2D() call. Even though an internal format can be selected that has a lower resolution than the source texture image, format must be set to the appropriate type for the source texture data regardless of what internalformat is set too.

Examples
Internal format : GL_RGB | Internal format : GL_RGB4
Notice the banding on the RGB4 texture which is absent on the RGB texture, this visual artifact is a tradeoff for having a lower memory requirement for the texture.

Conclusion

Well that's the end of this little article, I hope you enjoyed it. OpenGL's texture mapping functions give you a great deal of power over what happens with your textures, taking advantage of this power is important when writing OpenGL applications. Hopefully by reading this article you have gained some knowledge about the OpenGL texture mapping functions and how they can be used to achieve different results. If you find any errors in this document please let me know so that I can fix them as soon as possible.

References

- Texture Internal Formats
- OpenGL Man Pages
- SIGGRAPH `99 Course Notes
- The Redbook

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.