PDA

View Full Version : help understanding glVertexAttribPointer?



nondescript
07-21-2014, 04:36 PM
i am a newbie at Open GL and came here to clear out a confusion i had. I appreciate any help!


private int vbo;
private int ibo;

vbo = glGenBuffers();
ibo = glGenBuffers();

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, Util.createFlippedBuffer(vertices), GL_STATIC_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, Util.createFlippedBuffer(indices), GL_STATIC_DRAW);




glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
//glEnableVertexAttribArray(2);

//glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, false, Vertex.SIZE * 4, 0);
glVertexAttribPointer(1, 2, GL_FLOAT, false, Vertex.SIZE * 4, 12);
//glVertexAttribPointer(2, 3, GL_FLOAT, false, Vertex.SIZE * 4, 20);

//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_INT, 0);

glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
//glDisableVertexAttribArray(2);



The vertex shader code looks like


#version 330

layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;

out vec2 texCoord0;

uniform mat4 transform;

void main()
{
gl_Position = transform * vec4(position, 1.0);
texCoord0 = texCoord;
}


So, here is my understanding. The purpose of glVertexAttribPointer is to define the format of data in the vertex buffer object. So, in vbo it stores data as follows



buffer.put(vertices[i].getPos().getX());
buffer.put(vertices[i].getPos().getY());
buffer.put(vertices[i].getPos().getZ());
buffer.put(vertices[i].getTexCoord().getX());
buffer.put(vertices[i].getTexCoord().getY());
buffer.put(vertices[i].getNormal().getX());
buffer.put(vertices[i].getNormal().getY());
buffer.put(vertices[i].getNormal().getZ());


So, we have two glVertexAttribPointer lines because we have two variables defined in the vertex shader. So basically we are defining what these two variables point to. So, the first glVertexAttribPointer defines that the first variable "position" is a vertex with three coordinates each being float. The second glVertexAttribPointer defines the second variable "texCoord" being a pair of texture coordinates each being float. So, if my understanding is correct so far then i was assuming we first need to bind the vertex buffer object first but even after commenting out this line

glBindBuffer(GL_ARRAY_BUFFER, vbo);

it still works. I am confused. How does it know which buffer object we are talking about since there are two vbos?

I appreciate any help. Thanks a lot!

MtRoad
07-21-2014, 06:13 PM
Commenting out glBindBuffer(GL_ARRAY_BUFFER, vbo); doesn't change anything because the GL_ARRAY_BUFFER remains bound until you bind another array buffer or do: glBindBuffer( GL_ARRAY_BUFFER, 0 ); This is the same as for GL_ELEMENT_ARRAY_BUFFER except it remains bound until glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ) or another element array buffer is bound.

GL_ARRAY_BUFFER is the vertex buffer object which contains object vertex data (e.g. positions, normals, u-v coordinates, etc.) It is separate from GL_ELEMENT_ARRAY_BUFFER, which contains indices into the vertex data describing what vertices to pick to make the object. Both GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER bind to their own targets and are independent.

I can't come up with a rationale for doing so, but you could create two objects with the same vertex data and then just change the index arrays to create a different object by changing the bound GL_ELEMENT_ARRAY_BUFFER.

Ed Daenar
07-21-2014, 06:18 PM
VertexAttribPointer provides a way of telling GL how to extract data from a data stream you provide to pass it as a shader attribute input. With it you tell GL where the data is located (the target buffer bound to GL_ARRAY_BUFFER), the number of components, type of data (float, int, etc), how it's organized within the buffer (could be tightly packed or as part of a bigger structure) and the point in the buffer where it has to start fetching data.

This is what the man pages have to say about your question:



If pointer is not NULL, a non-zero named buffer object must be bound to the GL_ARRAY_BUFFER target (see glBindBuffer), otherwise an error is generated. pointer is treated as a byte offset into the buffer object's data store. The buffer object binding (GL_ARRAY_BUFFER_BINDING) is saved as generic vertex attribute array state (GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING) for index index.


Buffers, the things you create with glGenBuffers to later on fill with generic data are really just that, blocks of data. GL has certain "binding points" where you can hook these buffers and apply operations that expect a buffer to be bound to such binding points. When you bind a buffer to a binding point, it remains bound there until you bind something else (or release it).

In your code, you bind "vbo" to GL_ARRAY_BUFFER and then use BufferData to fill data into the buffer bound to that point. You never release it from that point afterwards. Then eventually you call VertexAttribPointer, which also expects a buffer to be bound on this same binding point, thus finding the buffer you left bound there.

Notice, however, that VertexAttribPointer and EnableVertexAttribArray modify the state of the currently bound vertex array object (VAO), which you can create via GenVertexArrays and bind as current VAO with BindVertexArray.

You don't show your VAO code anywhere, so it's possible you are not working with one. I am unsure if this is allowed behavior (you'd have to read the complete spec for this), but if you call these methods without a VAO bound you are modifying the state of the implicit VAO (i.e. VAO 0).

By using a generated VAO, you would not call VertexAttribPointer or glEnableVertexAttribArray or need to bind the index array or any other buffer before Draw calls, as it would all be stored as VAO state. You'd only bind the VAO and then draw.

nondescript
07-23-2014, 01:33 PM
Thank you for the clarifications!