4

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.

Riot
  • 15,723
  • 4
  • 60
  • 67
  • Nothing obvious jumps out. You tried `glGetError()` to make sure that there's no error state? And you're sure that the shader is properly compiled and linked? The values you get from the `glGetAttribLocation()` calls look sane? You're using literal values for `glDisableVertexAttribArray()` instead of the locations you retrieved, but that won't do any harm in this case. – Reto Koradi May 22 '14 at 03:19
  • @RetoKoradi: the index values for the attribs are 1, 2 and 3 respectively; I have experimented assigning them different values and that works fine, although attempting to bind the index 0 to any attribute prevents the shaders from linking. ```glGetError()``` returns 0. The literals were a typo in pasting the code, I've edited to fix that now. – Riot May 22 '14 at 03:23
  • Linking fails if you set the location of one of the attributes to 0, using `glBindAttribLocation()`? That sounds bizarre. Did you check what you get with `glGetProgramInfoLog()` when that happens? Maybe that will give some hint on what's going on here. What platform are you running on? – Reto Koradi May 22 '14 at 04:35
  • @RetoKoradi: that's right, I can bind them to anything, eg. 3, 5, 7 and glGetAttribLocation returns that value from then on, but if I attempt to bind any of them to 0, I get ```Fragment shader(s) linked, vertex shader(s) failed to link.``` in the glGetProgramInfoLog(). Not very informative. I had assumed that 0 was a reserved value... should I definitely be able to bind 0? – Riot May 22 '14 at 14:15
  • Followup: I've just checked with a separate standalone program and I definitely cannot link a program with any attrib locations bound to 0. System is Win32, Opengl2.1, ATI hardware. – Riot May 22 '14 at 14:46
  • 1
    @Riot: *"`glLinkProgram` will also fail if the vertex shaders used in the program object contain assignments (not removed during pre-processing) to an attribute variable bound to generic attribute **zero** and to the conventional vertex position (`gl_Vertex`)."* As much as I hate to say this, I think the fact that nothing is drawn if the ***conventional*** vertex position array is not enabled is a driver bug, back then (GL 2.1) it was not common practice ***not*** to use the conventional vertex position. – Andon M. Coleman May 22 '14 at 22:24
  • @AndonM.Coleman: I think you're probably right. I'm going to test this out on a few other machines and see if the behaviour is consistent. Where did you find that quotation? – Riot May 23 '14 at 13:57
  • @Riot It is part of the OpenGL 2.1 specification, you can find the specs for all versions of GL [here.](http://www.opengl.org/registry/) – Andon M. Coleman May 23 '14 at 17:09
  • Oh man, I've read that spec back to back and I must have totally missed that. You should post this as an answer; it's almost certainly the cause of my issue. – Riot May 23 '14 at 20:20
  • 1
    @Riot: I actually don't see how the spec statement Andon M. Coleman quoted could be relevant in your case - you are not assigning anything to gl_Vertex or any of your input attribute in your vertex shader. I also have code which uses exclusively generic vertex attributes (and explicitely binds my position attribute to location 0), and it is running fine on an old 2.x capbable ATI (a Radeon X1600, iirc) on Windows. Can you show the complete shader source code? – derhass May 24 '14 at 16:35
  • @derhass: I take the spec as implying gl_Vertex is mandatory in opengl2.1; and that it's simply a driver bug that i'm able to specify my own "coords" attribute, but in actuality it just functions as if i'd bound the buffer and used glVertexPointer rather than glVertexAttribPointer. The full shader code is almost the same as what i posted: http://pastebin.com/eMjrSwgb - i have now replaced this with the functionally equivalent and presumably opengl2.1 compatible version here: http://pastebin.com/D6bp9rJq However, I may still be misunderstanding the problem... any ideas what else I can check? – Riot May 24 '14 at 17:09
  • 1
    @Riot: I hope this is not just a copy&paste error within that first pastbin site. If that is really the code you used, all can be explained, and I added an answer doing so. – derhass May 24 '14 at 17:17
  • Wow, you could have saved us a lot of time by posting the full shader code, particularly since it was only 3 more lines. Then we could have seen the obvious problem immediately. – Reto Koradi May 24 '14 at 19:41
  • *hangs head in shame* – Riot May 24 '14 at 20:24

1 Answers1

1

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.

derhass
  • 43,833
  • 2
  • 57
  • 78
  • Oh my god; how did i miss that... I knew it would be something incredibly obvious that I was overlooking. Thank you! – Riot May 24 '14 at 17:35