c++openglglslvertex-shadervertex-array

Generic vertex attribute buffer doesn't seem to work without glVertexPointer


I'm drawing an interleaved buffer - it is a generic vertex attribute buffer. The layout consists of three floats as a vertex coordinate, and two other float attributes, interleaved thus:

| float    | float    | float    | float   | float   |
| coords.x | coords.y | coords.z | attrib1 | attrib2 |
|_______vertex coordinates_______|_________|_________|

I expect to be able to draw this with just glVertexAttribPointer, and this does indeed seem to work - however, it only works if i also use glEnableClientState(GL_VERTEX_ARRAY) and glVertexPointer(), even though I'm not accessing gl_Vertex in the shader!

The minimal vertex shader (GLSL 1.20):

#version 120

attribute vec3 coords;
attribute float attrib1;
attribute float attrib2;

void main() {
  gl_Position = gl_ModelViewProjectionMatrix * vec4(coords.x, coords.y, coords.z, 1.0);
  // attrib1 and 2 are used here but this is not relevant
}

The code to draw the buffers:

// set up states
glUseProgram(shader);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
GLuint shader_att0 = glGetAttribLocation(shader, "coords");
GLuint shader_att1 = glGetAttribLocation(shader, "attrib1");
GLuint shader_att2 = glGetAttribLocation(shader, "attrib2");
glEnableVertexAttribArray(shader_att0);
glEnableVertexAttribArray(shader_att1);
glEnableVertexAttribArray(shader_att2);
// *** These two lines below should not be necessary: ***
//glEnableClientState(GL_VERTEX_ARRAY);
//glVertexPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), reinterpret_cast<void*>(0));
// *** ...but without them, nothing is drawn! ***
glVertexAttribPointer(shader_att0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), reinterpret_cast<void*>(0));                    // 0: vertex coords
glVertexAttribPointer(shader_att1, 1, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), reinterpret_cast<void*>(3 * sizeof(GLfloat))); // 1: attrib1
glVertexAttribPointer(shader_att2, 1, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), reinterpret_cast<void*>(4 * sizeof(GLfloat))); // 2: attrib2

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

// do the drawing
glDrawElements(GL_TRIANGLES, numverts, GL_UNSIGNED_INT, 0);

// revert all the states again
glUseProgram(0);
glDisableVertexAttribArray(shader_att0);
glDisableVertexAttribArray(shader_att1);
glDisableVertexAttribArray(shader_att2);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

Everything works fine in the code above if I uncomment the two annotated lines; otherwise, nothing is drawn.

This really has me stumped... have I missed some state change somewhere or is there something I'm forgetting to enable?

Edit: I'm not using a VAO, and there's no other state set up aside from what you see here. No textures or other buffers bound.


Solution

  • From your linked shader code in the comments:

    #version 120
    #pragma optimize(on)
    #pragma debug(on)
    
    attribute vec4 coords;    // we only input a vec3, so w defaults to 1.0
    attribute float lambertian_main;
    attribute float lambertian_side;
    
    varying float height;
    varying float lambertian_main_frag;
    varying float lambertian_side_frag;
    
    void main() {
      gl_Position = gl_ModelViewProjectionMatrix * coords;
      lambertian_main_frag = lambertian_main;
      lambertian_side_frag = lambertian_side;
      height = gl_Vertex.y;
    }
    

    You are using gl_Vertex here... And if it is used, it will always get attribute ID 0. This totally explains the behavior you have seen and described both in the question and the comments. Just use height = coords.y and everything will work like you expect it to.