Generic Vertex Attributes Problem - Alphabetized?

I am creating a normal map shader using GLSL and it requires 3 generic vertex attributes named Tangent, Binormal, and Normal. In debugging the shader, I’ve discovered a strange anomally that I don’t understand. I allow the compiler to bind the attribs to an index and it assigns them as follows:

Tangent = 1
Binormal = 2
Normal = 3

This is what I would expect, since 0 is not supposed to be used. However, when I query to see what the active attribute indexes are assigned to, using glGetActiveAttrib, I get the following:

0 = Binormal
1 = Normal
2 = Tangent
3 = gl_MultiTexCoord0
4 = gl_Vertex

After some analysis, I noticed that these appeared to be in alphabetic order. So I changed my code to add some attribs labeled A, B, and C. And then I proceeded to manually bind them out of sequence as follows:

A = 1
C = 2
B = 3

Querying the active attribtues returned the following:

0 = A
1 = B
2 = C
3 = gl_MultiTexCoord0
4 = gl_Vertex

So, clearly they are being sorted alphabetically. And they are bound to the wrong indices. However, for sanity’s sake, if I again call glGetAttribLocation after my query on the active indices, I get the original values of 1, 2, 3.

Can anyone explain to me what is going on here?

Seem logical to me.
get active attrib gives the list of available attributes.
get attrib location gives where those attributes are set in the index.

Really? Based on the technical specs and conventional logic, I would have thought that if I queried a specific index that I would get back the name of the attribute that I assigned to that particular index.

The compiler should attempt to pack active attributes, after taking into account the rest of the state.

For example, let’s say that your vertex shader reads Tangent, Binormal, and Normal. And you do some calculations and pass through three varyings to the fragment stage. Now, depending on what the fragment stage does, the work you did in the vertex stage might have been meaningless. That is-- if you don’t use all of the varyings, some of the attributes might not be active (consider that you can reuse one vertex shader with several fragment shaders.)

Because the compiler does this kind of dependancy analysis, the resulting active attributes may be different than the attributes you’ve enabled and defined in the shader. Even if they are all used, there is no guarantee about the order, and the spec says as much:

GetActiveAttrib

Note that index
simply identifies a member in a list of active attributes, and has no relation to the
generic attribute that the corresponding variable is bound to.

To minimise state switching, you should be more carefull about attribute location… say… you have some large mesh stored in VBO. Vertex is:
vec3 pos;
vec3 norm;
vec2 tex0;
vec3 tangent;
vec3 binormal;
vec4 bone_indices; // in case of soft skinning
vec4 bone_wieights; // in case of soft skinning

And you have to draw a lot of meshes with different shaders…
So… bind your VBO, bind attribute pointers, and… wait? what if attributes change locaation in two different shaders? Well to keep them aligned as application wants, use glBindAttribLocationARB before linking shader.
So… define attribute names (and stick to that naming convention), and their location in attributes array. For each custom attribute, call glBindAttribLocationARB before linking avery shader.

With this approach, you can bind VBO once, set pointers and change shaders and draw as you want.

Even more… when you bind VBO and setup attribute pointers & enable client states you should not disable client states on unused attributes if some shader doesnt use all attributes.

btw, instead of specifying all of the data, calculate a binormal with a cross product.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.