PDA

View Full Version : glVertexAttrib() problem



ugluk
12-18-2009, 12:42 PM
I want to avoid the problems that will come about with OpenGL3.2 and it's dropping of glVertex().

for this reason I do the following:

glBegin(GL_TRIANGLES);
glVertexAttrib3f(0, ...); // vertex coordinates
glVertexAttrib2f(1, ...); // texture coordinates

glVertexAttrib3f(0, ...); // vertex coordinates
glVertexAttrib2f(1, ...); // texture coordinates

glVertexAttrib3f(0, ...); // vertex coordinates
glVertexAttrib2f(1, ...); // texture coordinates

// more such calls for more triangles
glEnd();

The triangles appear to be rendered at correct coordinates but only the first triangle is textured correctly, all others are textured incorrectly. It looks as if t was interpolated incorrectly. What kind of mistake am I making? Here are my bare-bones shaders.

// vertex shader
uniform mat4 model_view_matrix;
uniform mat4 projection_matrix;

in vec3 in_position;
in vec2 in_texcoords;

varying vec2 out_texcoords;

void main()
{
out_texcoords = in_texcoords;

gl_Position = projection_matrix * model_view_matrix *
vec4(0.5 * in_position, 1);
}

// fragment shader
uniform sampler2D texture0;

in vec2 out_texcoords;

void main()
{
gl_FragColor = texture2D(texture0, out_texcoords);
}

Alfonse Reinheart
12-18-2009, 12:49 PM
You have the attributes backwards.

Whenever you send glVertexAttrib(0), it acts like glVertex(). Which means that, in addition to sending the attribute data to attribute 0, it causes all prior attributes to combine into a single vertex (ie: causes the execution of the vertex shader).

So if we look at your code through the eyes of OpenGL:



glBegin(GL_TRIANGLES);
//First vertex
glVertexAttrib3f(0, ...); // vertex coordinates

//Second vertex
glVertexAttrib2f(1, ...); // texture coordinates
glVertexAttrib3f(0, ...); // vertex coordinates

//Third vertex
glVertexAttrib2f(1, ...); // texture coordinates
glVertexAttrib3f(0, ...); // vertex coordinates

//Fourth vertex
glVertexAttrib2f(1, ...); // texture coordinates
// more such calls for more triangles
glEnd();


You need to call glVertexAttrib(0) as the last data for a particular vertex.

ugluk
12-18-2009, 01:30 PM
And of course you are perfectly right. I see it only now in the spec. Thank you.

apapaxionga
04-02-2011, 08:28 PM
i got the same question ,but i do not understand your explaination very well,can you explain that in detail?why the triangle should be drawn like that ?

Alfonse Reinheart
04-02-2011, 09:08 PM
why the triangle should be drawn like that ?

Short answer: Because that's how OpenGL works. There is no "why."

Longer answer: Because OpenGL had to have some way for the user to say, "I've given you a bunch of vertex data. Now process that vertex."

glVertexAttrib sets state. It sets the current attribute value to the given value. You can think of this state as a C/C++ struct:



struct VertexAttribData
{
vec4 attribs[16];
};
VertexAttribData glContextAttribs;


Therefore, glVertexAttrib just does this:



void glVertexAttrib4f(attribIx, float xValue, float yValue, float zValue, float wValue)
{
glContextAttribs.attribs[attribIx].x = xValue;
glContextAttribs.attribs[attribIx].y = yValue;
glContextAttribs.attribs[attribIx].z = zValue;
glContextAttribs.attribs[attribIx].w = wValue;
}


That sets state. It sets values into the struct. But OpenGL doesn't know when you've finished setting values into that struct. That is, you need a way to tell OpenGL to take the glContextAttribs and process it as a vertex.

In the oldest days of OpenGL, there weren't numbered attributes. There were specific attributes that had a specific meaning. glTexCoord, glNormal, glVertex, etc. They still set values into a struct; you can think of them has having an implicit attribute index.

By convention, OpenGL decided that calls to "glVertex" didn't just set data. The function(s) also told OpenGL to "use the attribute values to render stuff."

Well, when you're working with generic attributes and GLSL, you don't use "glVertex." In order to preserve the ability to use immediate mode (glBegin()/glEnd()) rendering with GLSL and generic attributes, they had to establish a new way to tell OpenGL to "use the attribute values to render stuff."

By convention, that new way was the setting of attribute 0 to a value. That is, any glVertexAttrib(0, ...) call would have the effect of not just setting state but also using the current attributes to render.

They could have chosen to add a specific function for this purpose. Maybe call it "glProvokeVertex". And maybe they should have. But they didn't; they decided to use the convention of setting attribute 0. This is analogous to how vertex data worked before generic attributes, since glVertex would set state and cause rendering. But it also means that you must always have an attribute 0.