OpenGL Distilled

6.3. Debugging

Several things could cause texture mapping not to work properly, and there are numerous ways to identify the source of the problem.

6.3.1. OpenGL Error Code

Check for OpenGL errors after creating texture objects and after rendering each frame. When developing a new application, check for OpenGL errors early in development. This helps isolate the cause of the problem, because new errors are usually generated by new code. appendix D, "Troubleshooting and Debugging," describes the OGLDIF_CHECK_ERROR CPP macro, defined and used in the example code, which calls glGetError() without affecting application performance.

6.3.2. Texture State

New OpenGL programmers frequently confuse texture unit state and texture object state. Some of this confusion stems from OpenGL's history, because many texture state parameters existed in OpenGL version 1.0 before the addition of texture objects in version 1.1 and multitexturing in version 1.3.

For a complete enumeration of texture object and texture unit state, refer to Tables 6.15 and 6.16 in The OpenGL Graphics System. The following sections summarize the most essential state items.

6.3.2.1. Texture Object State

OpenGL stores state parameters set by the glTexParameter*() commands in texture objects. Binding a texture object activates these parameter values. For a complete list of state parameters, see "glTexParameter" in OpenGL® Reference Manual. The most common parameters are listed here:

  • GL_TEXTURE_MIN_FILTER and GL_TEXTURE_MAG_FILTER

  • GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, and GL_TEXTURE_WRAP_R

  • GL_DEPTH_TEXTURE_MODE, GL_TEXTURE_COMPARE_FUNC, and GL_TEXTURE_COMPARE_MODE

  • GL_GENERATE_MIPMAP

6.3.2.2. Texture Unit State

OpenGL maintains most other texture state parameters on a per-texture-unit basis to allow each texture unit to operate on texture objects in a unique manner. A few of the most common parameters are listed here:

  • The currently bound texture object, set with glBindTexture(). Applications can query this (per unit) to retrieve the currently bound texture-object identifier. The following code, for example, shows how to determine which texture object is bound to GL_TEXTURE_2D for texture unit GL_TEXTURE0:

    glActiveTexture( GL_TEXTURE0 ); GLint texId; glGetIntegerv( GL_TEXTURE_BINDING_2D, &texId );

    To query the texture object bound to GL_TEXTURE_CUBE_MAP, use glGetIntegerv( GL_TEXTURE_BINDING_CUBE_MAP, &texId ).

  • Enable and disable state for GL_TEXTURE_2D and GL_TEXTURE_CUBE_MAP.

  • GL_TEXTURE_ENV_MODE.

  • Enable and disable state for GL_TEXTURE_GEN_S, GL_TEXTURE_GEN_T, GL_TEXTURE_GEN_R, and GL_TEXTURE_GEN_Q.

  • GL_TEXTURE_GEN_MODE for GL_S, GL_T, GL_R, and GL_Q.

  • GL_OBJECT_PLANE and GL_EYE_PLANE for GL_S, GL_T, GL_R, and GL_Q.

  • The texture matrix stacks, one for each texture unit. OpenGL transforms each texture coordinate set by the top of the texture-matrix stack for the set's texture unit.

6.3.3. Texture Completeness

If a texture object isn't complete, OpenGL behaves as though the associated active texture unit is disabled. As a result, OpenGL renders your geometry without texture mapping.

A complete texture object meets the following conditions:

  • Texture image dimensions must be positive.

  • If GL_TEXTURE_MIN_FILTER specifies a mipmap filter, the texture must be mipmap complete.

  • If the texture object was first bound to GL_TEXTURE_CUBE_MAP, the texture object must be cube complete. If the cube map uses mipmapping, the texture object must be cube mipmap complete.

6.3.3.1. Mipmap Complete

If your application specified or changed the base texture image while GL_GENERATE_MIPMAP was set to GL_TRUE, or if you used gluBuild2DMipmaps() to specify your texture images, OpenGL has already created a mipmap-complete texture object. If you're creating a mipmapped texture object manually, however, with individual calls to glTexImage2D() for each mipmap level, see Section 3.8.10, "Texture Completeness," of The OpenGL Graphics System for the list of mipmap-complete criteria.

The texture-object state parameter GL_TEXTURE_MIN_FILTER defaults to GL_NEAREST_MIPMAP_LINEAR, which is a mipmap filter mode. Beginners commonly fail to change this parameter from its default value and specify a single texture map without a complete mipmap pyramid. In this case, the texture object isn't mipmap complete.

To fix this problem, set the minification filter to a nonmipmapped filter:

glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR );

If the OpenGL version is 1.4 or later, you can also enable mipmap generation before calling glTexImage2D(), so that OpenGL will create a complete mipmap pyramid for you when you specify the base texture image:

glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_TRUE );

6.3.3.2. Cube Complete

Your application must create cube map texture objects with six consistent images. A cube-complete texture object must meet the following criteria:

  • Each of the six images must have the same positive dimensions, and the width and height must be the same; each image must be square.

  • All six faces must have the same internal format.

  • All six faces must have the same border width.

  • To be cube-mipmap complete, each of the six faces must be mipmap complete when considered individually. (If the texture object's minification filter is a mipmap filter, all texture images must be mipmap complete.)

6.3.4. Missing Textures

There are many ways to misconfigure OpenGL accidentally, resulting in missing textures. The following paragraphs describe a few of the most common mistakes.

Make sure that you've enabled texture mapping. If the texture object bound to the active texture unit is 2D, call glEnable( GL_TEXTURE_2D ), and if the texture object is a cube map, call glEnable( GL_TEXTURE_CUBE_MAP ). If you're using multitexturing, make sure you enable each texture unit in use (conversely, be sure to disable texture units that are not in use).

When you enable texture mapping for a certain mode, disable other texture mapping modes. If the bound texture object contains a 2D texture image, for example, your code should ensure that GL_TEXTURE_1D, GL_TEXTURE_3D, and GL_TEXTURE_CUBE_MAP are all disabled. This is more than just good practice; the texture enumerants specify precedence. If GL_TEXTURE_CUBE_MAP is enabled, for example, but the bound texture object is 2D, OpenGL behaves as though texture mapping is completely disabled.

Unfortunately, there's no way to query OpenGL as to whether a texture object meets the texture-completeness criteria described in the section "Texture Completeness" earlier in this chapter. If you've accidentally bound a texture object that isn't texture complete, however, OpenGL will behave as though the active texture unit has texture mapping disabled.

Make sure that you set the appropriate texture environment for each enabled texture unit. Suppose that your application set GL_TEXTURE_ENV_MODE to GL_MODULATE for GL_TEXTURE0 and to GL_REPLACE for GL_TEXTURE1. In this case, the texture bound to GL_TEXTURE1 replaces the result from GL_TEXTURE0, and the final rendered image appears as though texture unit GL_TEXTURE0 is disabled.

6.3.5. Inverted Textures

The OpenGL window-coordinate system follows the Cartesian model of having its origin at the bottom-left corner, with positive x to the right and positive y up. Chapter 3, "Transformation and Viewing," briefly covers how this system clashes with most modern window systems, which have their origin in the top-left corner. This inconsistency causes headaches for most new OpenGL programmersuntil they learn how to address this problem.

Similarly, the OpenGL pixel pipeline expects the bottom row of pixels first and the top row last. Many image files, however, store their pixel data inverted from the OpenGL system, with the top row of pixels first and the bottom last. As a result, whether using glDrawPixels() or texture mapping, the pixel data appears upside down in the final rendered image.

OpenGL programmers generally use one of two methods to address this issue:

  • When designing the code that specifies texture coordinates, plan for this issue, and invert the images (or the texture coordinates).

  • Invert the t coordinate by using the texture matrix. The best way to do this depends on the t coordinate wrap mode. For GL_REPEAT, for example, you can use a simple scale transformation:

    glMatrixMode( GL_TEXTURE ); glLoadIdentity(); glScalef( 1.f, -1.f, 1.f );

    For a quadrilateral rendered with unit-texture coordinates at each vertex, as in the SimpleTextureMapping example, the above transformation produces 1 for t at the top of the image and 0 for t at the bottom, which inverts the image if the t coordinate wrap mode is GL_REPEAT. If the t coordinate wrap mode is GL_CLAMP_TO_EDGE, however, scaling t by 1 probably is insufficient, and you'd also need to translate in t, as shown below:

    glMatrixMode( GL_TEXTURE ); glLoadIdentity(); glScalef( 1.f, -1.f, 1.f ); glTranslatef( 0.f, 1.f, 0.f );

OpenGL implementations typically optimize for an identity texture matrix by eliminating the texture-coordinate transformation. So unless your application already uses the texture matrix, the second option incurs a per-vertex texture-coordinate transformation that could affect application performance.

Категории