Some terminology is a bit off:
- A
Vertex Array is just an array (usually a float[] ) that contains vertex data. This does not have to be associated with anything. Not to be confused with Vertex Array Object or VAO, which I will move on later. - A
Buffer Object , commonly called a Vertex Buffer Object when storing vertices, or shorting to VBO, is what you call only Buffer . - Nothing goes back to the vertex array,
glVertexAttribPointer works just like glVertexPointer or glTexCoordPointer , just instead of the named attributes you get a number that indicates your own attribute. You pass this value as index . All your calls to glVertexAttribPointer are queued the next time you call glDrawArrays or glDrawElements . If you have a VAO binding, VAO will save the settings for all your attributes.
The main problem here is that you are mixing vertex attributes with VAO. Vertex attributes are just a new way of defining vertices, tekscodes, normals, etc. For drawing. VAO store status. First, I will explain how a drawing with vertex attributes works, and then explain how you can reduce the number of method calls using VAO:
- You must enable the attribute before you can use it in the shader. For example, if you want to send vertices to the shader, you will most likely send it as the first attribute of 0. So, before rendering, you need to enable it with
glEnableVertexAttribArray(0); . - Now that the attribute is enabled, you need to determine the data that it will use. To do this, you need to bind your VBO -
glBindBuffer(GL_ARRAY_BUFFER, myBuffer); . - And now we can define the attribute -
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); . In the order of the parameter: 0 - the attribute that you define, 3 - the size of each vertex, GL_FLOAT - type, GL_FALSE means not normalize each vertex, the last 2 zeros mean that there is no step or offset on the vertices. - Draw something with it -
glDrawArrays(GL_TRIANGLES, 0, 6); - The next thing you draw may not use the attribute 0 (it really will be, but this is an example), so we can disable it -
glDisableVertexAttribArray(0);
Wrap this in glUseProgram() calls, and you have a rendering system that works with shaders properly. But suppose you have 5 different attributes, vertices, techcodes, normals, colors, and lightmap coordinates. First of all, you have to make one glVertexAttribPointer call for each of these attributes, and you will need to include all the attributes in advance. Let's say you define attributes 0-4 as I list them. You would include them all like this:
for (int i = 0; i < 5; i++) glEnableVertexAttribArray(i);
And then you have to bind different VBOs for each attribute (if you do not save them all in one VBO and do not use offsets / steps), then you need to make 5 different calls to glVertexAttribPointer , from glVertexAttribPointer(0,...); up to glVertexAttribPointer(4,...); for vertices in lightmap coordinates respectively.
Hope this system makes sense. Now I will move on to VAO to explain how to use them to reduce the number of method calls when performing this type of rendering. Please note that the use of VAO is not required.
A Vertex Array Object or VAO is used to store the state of all calls to glVertexAttribPointer and VBOs that were targeted when all calls to glVertexAttribPointer were made.
You create one with a call to glGenVertexArrays . To save everything you need to VAO, bind it with glBindVertexArray , then make a full draw call . All draw binding calls are intercepted and saved by the VAO. You can untie the VAO with glBindVertexArray(0);
Now that you want to draw an object, you donβt need to rewrite all VBO bindings or glVertexAttribPointer calls, you just need to bind VAO to glBindVertexArray , then call glDrawArrays or glDrawElements , and you will draw the same thing as all these method calls. You probably want to untie the VAO again.
Once you untie the VAO, the whole state will return to what it was before you linked the VAO. I'm not sure that any changes you make during VAO are saved, but this is easy to understand with a test program. I think you can come up with glBindVertexArray(0); as binding to VAO by default ...
Update: Someone drew my attention to the need to call a call. As it turned out, in fact, you do not need to do a FULL draw call when setting up VAO, just all the necessary things. I donβt know why I thought it was necessary before, but now itβs fixed.