Search code examples
openglglsl

GLSL Layout works strange


There are 2 layouts in my vertex shader

layout (location = 1) in vec3 aColor;
layout (location = 0) in vec3 aPos;

I set them by func glVertexAttrib3f();

glVertexAttrib3f(1, 0, 1, 0); // color

glBegin(GL_TRIANGLES); // vertexes
glVertexAttrib3f(0, 0, 0, 0);
glVertexAttrib3f(0, 1, 0, 0);
glVertexAttrib3f(0, 1, 1, 0);
glEnd();
    

In this situation, everything is ok, I have my green triangle in a window. But if I swap my aPos layout and aColor (set 1 to aPos and 0 to aColor)

layout (location = 0) in vec3 aColor;
layout (location = 1) in vec3 aPos;

and also dont forgot to swap them in my cpp file

glVertexAttrib3f(0, 0, 1, 0); // color

glBegin(GL_TRIANGLES); // vertexes
glVertexAttrib3f(1, 0, 0, 0);
glVertexAttrib3f(1, 1, 0, 0);
glVertexAttrib3f(1, 1, 1, 0);
glEnd();

nothing dont work and my window is empty (it must draw green triangle) Why it works so?


Solution

  • Calling glVertexAttrib with an index of 0 is a special kind of command: It will result in a vertex being emitted using all the vertex attributes previously set.

    See OpenGL 2.0 specification (where glVertexAttrib was introduced) section 2.7. "Vertex Specification":

    Setting generic vertex attribute zero specifies a vertex; the four vertex coordinates are taken from the values of attribute zero. A Vertex2, Vertex3, or Vertex4 command is completely equivalent to the corresponding VertexAttrib* command with an index of zero. Setting any other generic vertex attribute updates the current values of the attribute. There are no current values for vertex attribute zero

    When you do:

    glVertexAttrib3f(1, 0, 1, 0); // color
    glVertexAttrib3f(0, 0, 0, 0);
    glVertexAttrib3f(0, 1, 0, 0);
    glVertexAttrib3f(0, 1, 1, 0);
    

    then essentially you emit three vertices with their index=1 attribute having the value (0, 1, 0).

    On the other hand, when you do:

    glVertexAttrib3f(0, 0, 1, 0); // color
    glVertexAttrib3f(1, 0, 0, 0);
    glVertexAttrib3f(1, 1, 0, 0);
    glVertexAttrib3f(1, 1, 1, 0);
    

    then what happens is that you first emit one vertex with all its attributes having their default/zero values and then set the value of the vertex attribute with index=1 to effectively (1, 1, 0) (the last call). That will only be really used whenever you emit another vertex by calling glVertexAttrib3f(0, ...).

    So, the bottom line is: The vertex attribute with index 0 has a special meaning in that it will also emit a vertex. So a call with glVertexAttrib3f(0, ...) should always be the last call per vertex after all the other attributes for that vertex have been set.