What's the difference between glClient*** gl***?
I'm learning GLES. There are 开发者_Python百科many pair functions like glClientActiveTexture
/glActiveTexture
.
What's the difference between them? (Especially the case of glClientActiveTexture
)
From the openGL documentation:
- glActiveTexture glActiveTexture selects which texture unit subsequent texture state calls will affect.
- glClientActiveTexture selects the vertex array client state parameters to be modified by glTexCoordPointer.
On one hand, glClientActiveTexture is used to control subsequent glTexCoordPointer calls (with vertex arrays). On the other hand glActiveTexture affects subsequent calls to glTexCoord calls (used by display lists or immediate mode (non existent in OpenGL ES (AFAIK)).
Adding to Kenji's answer, here's a bit more detail (and bearing in mind that not everything in OpenGL is available in ES).
Terminology
But first some quick terminology to try to prevent confusion between all the texturish things (oversimplified for the same reason).
- Texture Unit: A set of texture targets (e.g.
GL_TEXTURE_2D
). It is activated viaglActiveTexture
- Texture Target: A binding point for a texture. It specifies a type of texture (e.g. 2D). It is set via
glBindTexture
. - Texture: A thing containing texels (image data, e.g. pixels) and parameters (e.g. wrap and filter mode) that comprise a texture image. It is identified by a key/name/ID, a new one of which you get via
glGenTextures
, and it is actually instantiated via (first call to)glBindTexture
with its name.
Summary: A texture unit has texture targets that are bound to textures.
Texture Unit Activation
In order to have multitexturing with 2D textures (for example), wherein more than one 2D texture must be bound simultaneously for the draw, you use different texture units - bind one texture on one unit's 2D target, and bind the next on another unit's 2D target. glActiveTexture
is used to specify which texture unit the subsequent call to glBindTexture
will apply to, and glBindTexture
is used to specify which texture is bound to which target on the active texture unit.
Since you have multiple textures, you're likely to also have multiple texcoords. Therefore you need some way to communicate to OpenGL/GLSL that one set of texcoords is for one texture/unit, and another set of texcoords is for another. Usually you can do this by just having multiple texcoord attributes in your vertex and corresponding shader. If you're using older rendering techniques that rely on pre-defined vertex attributes in the shader, then you have to do something different, which is where glClientActiveTexture
comes in. The confusion happens because it takes an argument for a texture unit, but it does not have the same implications as glActiveTexture
of activating a texture unit in the state machine, but rather it designates which pre-defined gl_MultiTexCoord
attribute (in the shader) will source the texcoords described in the subsequent call to glTexCoordPointer
.
In a nutshell, glActiveTexture
is for texture changes, and glClientActiveTexture
is for texcoord changes. Which API calls you use depends on which rendering technique you use:
glActiveTexture
sets which texture unit will be affected by subsequent context state calls, such asglBindTexture
. It does not affectglMultiTexCoord
,glTexCoord
, orglTexCoordPointer
, because those have to do with texcoords, not textures.glClientActiveTexture
sets which texture unit subsequent vertex array state calls apply to, such asglTexCoordPointer
. It does not affectglBindTexture
, because that has to do with textures, not texcoords.- It also does not affect
glMultiTexCoord
which uses DSA to select a texture unit via its target parameter, nor does it affectglTexCoord
, which targets texture unit 0 (GL_TEXTURE0
). This pretty much just leavesglTexCoordPointer
as the thing it affects, andglTexCoordPointer
is deprecated in favor ofglVertexAttribPointer
, which doesn't needglClientActiveTexture
. As you can see,glClientActiveTexture
isn't the most useful, and is thusly deprecated along with the related glWhateverPointer calls.
- It also does not affect
- You'll use
glActiveTexture
+glBindTexture
with all techniques to bind each texture on a specific texture unit. You'll additionally useglClientActiveTexture
+glTexCoordPointer
when you're using DrawArrays/DrawElements withoutglVertexAttribPointer
.
Multitexturing Examples
As OpenGL has evolved over the years, there are many ways in which to implement multitextured draws. Here are some of the most common:
- Use immediate mode (
glBegin
/glEnd
pairs) with GLSL shaders targeted for version 130 or older, and useglMultiTexCoord
calls to specify the texcoords. - Use
glBindVertexArray
andglBindBuffer
+glDrawArrays
/glDrawElements
to specify vertex data, and calls toglVertexPointer
,glNormalPointer
,glTexCoordPointer
, etc., to specify vertex attributes during the draw routine. - Use
glBindVertexArray
+glDrawArrays
/glDrawElements
to specify vertex data, with calls toglVertexAttribPointer
to specify vertex attributes during the init routine.
Here are some examples of the API flow for multitexturing with two 2D textures using each of these techniques (trimmed for brevity):
Using immediate mode:
- init
- draw
- shutdown
- vertex shader
- fragment shader
Using DrawElements but not VertexAttribPointer:
- init
- draw
- shutdown
- vertex shader (same as immediate mode)
- fragment shader (same as immediate mode)
Using DrawElements and VertexAttribPointer:
- init
- draw
- shutdown
- vertex shader
- fragment shader
Misc. Notes
glMultiTexCoord
populates unused coords as 0,0,0,1. e.g.glMultiTexCoord2f
== s,t,0,1- Always use
GL_TEXTURE0
+ i, not just i. - When using
GL_TEXTURE0
+ i, i must be within 0 -GL_MAX_TEXTURE_COORDS
-1. GL_MAX_TEXTURE_COORDS
is implementation-dependent, but must be at least two, and is at least 80 as of OpenGL 4.0.glMultiTexCoord
is supported on OpenGL 1.3+, or with ARB_multitexture- Do not call
glActiveTexture
orglBindTexture
betweenglBegin
andglEnd
. Rather, bind all needed textures to all needed texture units before the draw call.
精彩评论