|
With the
advent of the OpenGL 1.1 specification, texture objects became part of
the API. These texture objects have been available for quite some time
as extensions to OpenGL 1.0 because of their incredible performance benefits.
However, not everyone is aware of what texture objects are and why they
are useful. Texture objects can improve your textured rendering performance
by more than 10 times using the same hardware. That's a pretty bold claim,
and I can demonstrate it with ease.
Typically,
you load a texture image from either a disk file or a memory resource,
or you generate it procedurally. You then upload the texture to OpenGL
with a call to glTexImage2D(). Although I'm using 2D textures for this
working example, everything that this article discusses applies equally
well to 1D and 3D (OpenGL 1.2 only) textures. A typical scenario would
go something like this:
1. Load
texture image bits from a disk file.
2. Set the
OpenGL texture parameters and environment (filters, border modes, and
so on).
3. Call
glTexImage2D (for 2D textures) to load the texture into OpenGL.
4. Draw
some geometry with texture coordinates.
However,
you wouldn't want to perform each of these steps for every frame of an
animated scene. Repeatedly accessing a disk file can be pretty expensive,
time wise. If you were using a single texture, you might first load the
disk file and call glTexImage2D() after creating the rendering context.
Then you'd render the geometry or scene while repeatedly changing the
viewer's position or the object's orientation (whichever is appropriate).
With a run-of-the-mill 3D card with OpenGL acceleration, you would get
a reasonably good frame rate and thus a smooth animation.
Now suppose
that a given scene contains multiple textured objects, each using one
or more textures; or perhaps a single object with multiple textures. For
our example, we'll use a spinning cube with a different texture on each
face, plus a marble texture for the floor beneath this cube. This scene
has a total of seven textures that need to be loaded.
Naturally,
we don't want to access the disk seven times for every frame of our animation,
as this would slow our rendering considerably. One popular technique is
to combine all seven textures into one large texture that gets loaded
once. Then, by tweaking the texture coordinates, you can effectively put
different portions of the same texture on each side of the cube. The problem
with this technique is that texture filtering will often introduce unsightly
artifacts along the edges of your polygons. Another practical consideration
is that most hardware imposes some limit on the maximum texture size for
a single texture. You could quickly exhaust your available texture space
without making much of a dent in your actual available texture memory.
So artistically,
it's better to keep textures separate. How then do we avoid a texture
load every time we need to change textures? A reasonable and intuitive
choice would be to use display lists. Each display list would contain
a call to glTexture2D() (or 1D or 3D) with the appropriate pointer for
the given texture. This approach would save considerable time because
it only accesses the disk seven times to read in the textures and does
so before the animation loop. Saving seven or more disk accesses per frame
seems to be a substantial optimization. Let's see what happens.
|