VertexArrayObject question

Started by oglun, August 14, 2011, 11:06:34

Previous topic - Next topic

oglun

Hi all

I have an OpenGL noob question: As far as I have understand it, to draw something in OpenGL I need a shader program which has some attributes. This attributes are information the shader can use to draw something. The location of a vertex is one of these attributes. This implies: If I have a shader with no attributes (for the location) I cannot draw a vertex with that particular shader.
So, I need to connect my vertex with attribute data.
One step is to transferm the locations of the locations from client memory to the graphics hardware. As far as I understand it, I need buffer objects for this:
vertexArrayName = glGenBuffers()
glBindBuffer(GL_ARRAY_BUFFER, vertexArrayName)
glBufferData(GL_ARRAY_BUFFER, vVerts, GL_DYNAMIC_DRAW)


Which raises another question/assumption: If I use glBufferData to write data to a buffer, the buffer the data is written too, is the last binded buffer.
Now I need to connect these attribute data with my vertices. To do that, I have the following code:
glEnableVertexAttribArray(attribArrayIndex)
glBindBuffer(GL_ARRAY_BUFFER, vertexArrayNameFromAbove)
glVertexAttribPointer(attribArrayIndex, 3, GL_FLOAT, false, 0, 0)


I’m not sure I understand this code correctly: I first have to enable a vertex attribute array for a specified index. This means to me: I have several attributes and an attribute is an array.
Next I have to bind the buffer with the location data of the vertices.  Then, I have to tell OpenGL that the first attribute of my attribute array, has 3 components of type float.
One of my questions is why do I have to bind the buffer with the locations now?  It’s obvious OpenGL connects the data of the buffer with the vertex attribute but how?
Now the last bit is the rendering itself:
glBindVertexArray(vertexArrayObject)
glDrawArrays(GL_TRIANGLES, 0, numVertices) //3 in this example
glBindVertexArray(0)


This puzzles me the most: the vertex array object. Before the code from above is executed I have to do the following:
vertexArrayObject = glGenVertexArrays()
glBindVertexArray(vertexArrayObject)


The OpenGL wiki say that the vertex array object “store the set of bindings between Vertex Attributes and the user's source vertex data” But I never actually write anything to this thing, I just Bind it and then do the other stuff from above. So again, OpenGL just does the magic stuff or how does this work? I cannot grasp this VAO, is this just some kind of a configuration object which is managed by OpenGL and I have just to say which one I want to use for a particular draw operation.

I’m sorry this posting is so long, I know long postings are a bit tedious but I hope an OpenGL guru will enlighten me. (-:

spasi

Quote from: oglun on August 14, 2011, 11:06:34Now I need to connect these attribute data with my vertices. To do that, I have the following code:
glEnableVertexAttribArray(attribArrayIndex)
glBindBuffer(GL_ARRAY_BUFFER, vertexArrayNameFromAbove)
glVertexAttribPointer(attribArrayIndex, 3, GL_FLOAT, false, 0, 0)


I’m not sure I understand this code correctly: I first have to enable a vertex attribute array for a specified index. This means to me: I have several attributes and an attribute is an array.
Next I have to bind the buffer with the location data of the vertices.  Then, I have to tell OpenGL that the first attribute of my attribute array, has 3 components of type float.
One of my questions is why do I have to bind the buffer with the locations now?  It’s obvious OpenGL connects the data of the buffer with the vertex attribute but how?

The important detail here is the last param in glVertexAttribPointer; at the native level it's a simple void pointer. In the compatibility profile, this pointer could point to application memory and the vertex shader will source vertex data from that directly. Well, not exactly, there's lot of driver magic happening, but that is what it looks like from the developer point-of-view. Now, the confusing part is that the same function has been re-used for vertex buffer objects. When a VBO is currently bound, the semantics of the last param change; instead of a pointer to memory, it's an offset relative to the start of the VBO memory. So when you do:

glBindBuffer(GL_ARRAY_BUFFER, vertexArrayNameFromAbove)
glVertexAttribPointer(attribArrayIndex, 3, GL_FLOAT, false, 0, 0)


the vertex shader will start reading vertex data at the memory address: vertexArrayNameFromAbove.address + 0. Of course, the VBO memory could reside in GPU memory and that's exactly the point. You don't need to know where the VBO is, it's being managed by the OpenGL driver.

Anyway, this should explain why you need to bind the VBO before calling VertexAttribPointer.

Quote from: oglun on August 14, 2011, 11:06:34Now the last bit is the rendering itself:
glBindVertexArray(vertexArrayObject)
glDrawArrays(GL_TRIANGLES, 0, numVertices) //3 in this example
glBindVertexArray(0)


This puzzles me the most: the vertex array object. Before the code from above is executed I have to do the following:
vertexArrayObject = glGenVertexArrays()
glBindVertexArray(vertexArrayObject)


The OpenGL wiki say that the vertex array object “store the set of bindings between Vertex Attributes and the user's source vertex data” But I never actually write anything to this thing, I just Bind it and then do the other stuff from above. So again, OpenGL just does the magic stuff or how does this work? I cannot grasp this VAO, is this just some kind of a configuration object which is managed by OpenGL and I have just to say which one I want to use for a particular draw operation.

Vertex array objects exist because they enable more efficient rendering. VBOs were working just fine before GL3.0 (when VAO were introduced) but the driver overhead was greater without VAO. Before each draw call, you'd need 1 or more glBindBuffer calls (different attributes may be sourced from different VBOs) and a bunch of glVertexAttribPointer calls. The real inefficiency here is the glVertexAttribPointer call, there's a non-trivial amount of work that needs to be done by the driver every time. With VAO, this work needs to be done only once, like so:

// Load time
glBindVertexArray(vao);
glBindBuffer(vbo1)
glVertexAttribPointer(...)
glVertexAttribPointer(...)
glBindBuffer(vbo2)
glVertexAttribPointer(...)
...
glBindVertexArray(0);

// Render time
glBindVertexArray(vao);
glDrawElements(...);
glBindVertexArray(0);


Without VAO it would look like:

// Render time
glBindBuffer(vbo1)
glVertexAttribPointer(...)
glVertexAttribPointer(...)
glBindBuffer(vbo2)
glVertexAttribPointer(...)
...
glDrawElements(...);

oglun

Sorry for pushing this thread up, but I just want to say thank you for your insights. I see the things clearer now