The ARB_multitexture extension

Overview

Perhaps the most significant new OpenGL extensions to appear in the last year is ARB_multitexture.  Several new chips coming out this year will support multitexture, in addition to those already on the market.

While multipass rendering has been around for years, it really became mainstream when id Software release GLQuake in December 1996.  At the time, only one consumer-class chipset (Voodoo) had a sufficient pixel fill-rate to run GLQuake at acceptable fill rates.  Why was GLQuake so fill-rate hungry?  Because the majority of pixels in each frame were rendered twice; once with a base texture, and again with a light map.

What GLQuake really needed was a way to render with two separate textures in a single pass.

Which extension should I use?

It just so happened that the Voodoo2 supported just this kind of multi-texturing capability.  So 3DFx took the SGIS_multitexture extension spec, which was unfortunately still under development, and implemented enough of the extension to support GLQuake and Quake2. While this filled a short-term need for id Software and 3DFx, more multitexture capable hardware was soon to appear and the need for a multi-vendor extension spec was indicated.

In september of 1998, after several iterations and much debate, the ARB approved the first-ever ARB extension: ARB_multitexture.  An ARB extension differs from an EXT extension in that the ARB has formally reviewed and approved the extension.  (This is not to say that EXT extensions are somehow inferior, just that the ARB hasn't formally reviewed them.)

Unlike the half-baked and partially-implemented SGIS_multitexture extension, the ARB_multitexture extension has a conformance test and must be fully implemented on any hardware which advertises the extension string.  So use ARB_multitexture with confidence, and please don't write new code to the SGIS_multitexture spec.

Somewhere along the line another variant appeared; EXT_multitexture was simply a renaming of SGIS_multitexture, since only SGI is supposed to implemented SGIS extensions.  EXT_multitexture was only implemented in Mesa, and its use is discouraged now that ARB_multitexture has been adopted by all multitexture-capable implementations.

How does it work?

In standard OpenGL, the post-lighting fragment color feeds into the texture environment block for texture application.  If texture mapping is disabled, it simply passes through unchanged.

                   Ct |
                      V
                +---------+
                | Texture |
        Cf ---> |   Env   | ---> C'f
                +---------+

Multitexture is similar, except that multitexture texture environments (up to 32) are present:

                  Ct0 |            Ct1 |
                      V                V
                +---------+      +---------+
                | Texture |      | Texture |
        Cf ---> |  Env 0  | ---> |  Env 1  | ---> C'f
                +---------+      +---------+

To program a particular texture environment, use the command

glActiveTextureARB(GLenum texture);
Where texture is GL_TEXTUREn_ARB, 0 <= n < GL_MAX_TEXTURE_UNITS_ARB.

When you call glBindTexture(), the texture object is bound to the active texture unit specified by texture.  Likewise, enabling and disabling textures and modifying texture environment, texture matrix and texgen modes affect only the active texture unit. Modifying a texture array or parameters affects the texture object bound to the active texture unit, but such changes are visible to other texture units if the texture is bound to multiple texture units simultaneously.

For example, to bind and enable textures tex0 and tex1 on the first two texture units, use the following sequence:

glActiveTextureARB(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_2D, tex0);
glEnable(GL_TEXTURE_2D);

glActiveTextureARB(GL_TEXTURE1_ARB);
glBindTexture(GL_TEXTURE_2D, tex1);
glEnable(GL_TEXTURE_2D);

Each texture unit uses a seperate set of texture coordinates.  To specify texture coordinates for multiple texture units, use the command
glMultiTexCoord[1234][sifd][v](GLenum texture, ...);
where texture is GL_TEXTUREn_ARB.  You can still use glTexCoord*() for texture unit 0 if you prefer, as it might be slightly faster.  For example, to draw a triangle with two textures:
glBegin(GL_TRIANGLES);
glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, &t0[0]);
glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, &t1[0]);
glVertex3fv(&v[0]);

glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, &t0[1]);
glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, &t1[1]);
glVertex3fv(&v[1]);

glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, &t0[2]);
glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, &t1[2]);
glVertex3fv(&v[2]);

glEnd();
If you are using vertex arrays, you can set multiple sets of texture coordinates with the command
glClientActiveTextureARB(GLenum target);
which is the client state analog of glActiveTextureARB().  When manipulating vertex array state, glTexCoordPointer() and glEnableClientState() affect the client active texture indicated by target.  For example, to set up two texture coordinate arrays:
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glTexCoordPointer(2, GL_FLOAT, 0, tp0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glTexCoordPointer(2, GL_FLOAT, 0, tp1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
Now calls to glDrawArrays(), glDrawElements() or glArrayElement() will issue both sets of texture coordinates for each vertex.

What new texture blending capabilities are available?

The ARB_multitexture extension adds no new texture blending modes. The standard OpenGL 1.1 modes are supported in a pipelined manner; the result of the first texture environment feeds into the second texture environment as the fragment color.  For example, if the TEXTURE_ENV_MODE is MODULATE for texture units 0 and 1, the final result will be:
C'f = Cf * Ct0 * Ct1
More sophisticated blending capabilities do exist in current hardware, and will be exposed through a new set of extensions which are currently under development.



Copyright (c) 1999, Michael I. Gold