PDA

View Full Version : Understanding why we bind a VAO before a VBO



nublet42
12-05-2016, 03:32 PM
I've been reading a lot of tutorials but none of them explain why things happen the way they do, for example:


glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);

I don't understand why we have the VAO coming before the VBO. I can see from their descriptions why we have a VAO, but why it must come before calling glBindBuffer on a VBO doesn't make sense to me... what is going on
I'm also missing things like if we can make multiple VBO's and just call them as needed, or if we're supposed to create just one and load all our data into them and render based on vertex indices.

Where can I find this information? I wanted to read the OpenGL SuperBible but I'm worried based on the reviews that it's just going to give me a wrapper library and I won't understand the why's of how this works.

You'll have to deal with massive gaps in my knowledge, don't assume anything.

GClements
12-05-2016, 03:52 PM
I don't understand why we have the VAO coming before the VBO.

Because glVertexAttribPointer() modifies the state held in the currently-bound VAO.

You can bind the buffer and upload data without any VAO being bound, but you need to bind the VAO before calling glVertexAttribPointer() .

mhagain
12-05-2016, 04:07 PM
glBindVertexArray doesn't always need to come before glBindBuffer, but you typically see it come before in example and tutorial code.

OpenGL calls are executed in the order they're issued, and each of the glBind* calls typically do nothing other than tell OpenGL "this is the texture/buffer/VAO/whatever that is going to be used for future operations" (the first time you bind an object it will create one with default properties, but you can ignore that for the purposes of this explanation). Those future operations then pick up the bound objects and do something important or interesting with them.

So the critical OpenGL call in the code sample you give is actually glVertexAttribPointer.

When you call glVertexAttribPointer, what it does is interpret the parameters are relative to the currently bound buffer, and save off the state to the currently bound VAO. From this you can easily infer that it doesn't actually matter what order the buffer and VAO are bound in; what matters is that they are bound when glVertexAttribPointer is called.

There is of course an exception (isn't there always?): binding the GL_ELEMENT_ARRAY_BUFFER is actually different, and the current GL_ELEMENT_ARRAY_BUFFER is saved to the current VAO at the time it is bound. In that case, the VAO must be bound first.

Where can you find this kind of information? In the documentation for OpenGL functions (https://www.opengl.org/sdk/docs/man4/html/glVertexAttribPointer.xhtml), the extension documentation (https://www.opengl.org/registry/specs/ARB/vertex_array_object.txt), as well as in the OpenGL specification (https://www.opengl.org/registry/#apispecs) itself.

BBeck1
12-06-2016, 05:24 AM
I thought this was kind of an interesting question because it makes me think a bit. So, I looked at my code. Turns out, I declare it backwards from what you said and it works fine. I declare and bind vbo, vao, and ibo in that order.

I think you generally see it that way because it's kind of logical. Define what a vertex is. Then declare a buffer full of vertices. Then declare a buffer of indices to reference it. But it looks like the order you do that in is actually irrelevant as long as it's all done before the draw call.

The main OGL books are probably the most likely books to give you really in depth answers, but I find them to be difficult reading much like reading a dictionary or encyclopedia. I'm not sure of a book that has the exact answers you're looking for. Those books as reference books may be the best choice to answer a specific question. I just started reading red book cover to cover and it's, again, like reading an encyclopedia cover to cover.

Check out LearnOpenGL.com if you have not already. I'm always kind of on the lookout for new OGL learning material. That's one that's really impressed me.

Here's my code:


bool HandCodedObjectClass::DefineMesh(int NumberOfVertices, GLfloat* VertexList, int NumberOfIndices, GLuint* IndexList, Texture2DClass* ColorMap)
{
Texture = ColorMap;
VerticesInMesh = NumberOfVertices;
IndicesInMesh = NumberOfIndices;

glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, NumberOfVertices * sizeof(GLfloat) * 12, VertexList, GL_STATIC_DRAW);

glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 12, nullptr); //Vertex Position.
glEnableVertexAttribArray(0);

glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 12, (GLvoid*)(sizeof(GLfloat) * 3)); //Vertex UV.
glEnableVertexAttribArray(1);

glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 12, (GLvoid*)(sizeof(GLfloat) * 5)); //Vertex Normal.
glEnableVertexAttribArray(2);

glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 12, (GLvoid*)(sizeof(GLfloat) * 8)); //Vertex RGBA color.
glEnableVertexAttribArray(3);

glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*NumberOfIndices, IndexList, GL_STATIC_DRAW);


return true;
}