Vertex Array Object (VAO)
Last updated
Last updated
Some OpenGL users think that a Vertex Array Object (VAO)) in OpenGL is optional but it is not. If you use OpenGL 3.3+ you have to use a VAO not to cause an undefined behaviour, for example a crash. Before OpenGL draws anything it will use the current bound VAO to get the information about the data it will use to setup the shader channels and use the correct BO for the correct purpose.
You can imagine the meaning of the VAO as an object that holds references to one or multiple BO, a description how the VBO is structured, connection to the shaders attributes. In short, we can assign one/multiple VBO and one Index Buffer Object (IBO) to be precise and the good thing is, we just do all this (in the best case) only once and use the VAO multiple times. For example if we would have a 3D model for a car, a plane and a spaceship, we could setup 3 VAO for each of them once and then just bind the one we like to draw. We don't have to set anything else anymore.
Let's create an empty name for our VAO. We do that with glCreateVertexArrays:
The next thing we need to do is to tell OpenGL where to find the vertex data which means which VBO we want to use and how the shader can use it later. We do that with the following line using our VBO and vertex structure from above. We do that with glVertexArrayVertexBuffer:
Next is, we tell OpenGL how the shader will access those buffers. We do that with glVertexArrayAttribBinding:
In the first parameter we pass our VAO we want to set the attribute bindings which is vao. The second is the index used inside the shader. The third parameter is the binding index we used in glVertexArrayVertexBuffer.
Now we have to tell OpenGL how our VBO is structured. We do that with glVertexArrayAttribFormat:
Again, the 1. parameter is the VAOs name we like to modify. The 2. parameter is how the shader can access this element. This is done in the shader with the (layout = 0) directive. The 3. parameter tells how many components this type will have. For example the position values we are using in the VBO has x, y z components. So we use 3 here. The 4. parameter is information about the type. We are using float values. The 5. parameter can be use to say it the values should be normalized or not. The 6. parameter gives information about the distance between elements within the buffer. For x,y,z as floats we would have a relative offset of sizeof(float) * 3.
Next we have to set is the divisor with glVertexArrayBindingDivisor:
Finally we need to enable the attribute with glEnableVertexArrayAttrib:
Parameter
Type
Description
1
GLuint vaobj
The VAO name.
2
GLuint bindingindex
The binding point for the VBO. This is not the attribute index for the shader. We just tell OpenGL that we like to reference the VBO we will specify that it will be identified with this index.
3
GLuint buffer
The VBO name we like to bind.
4
GLintptr offset
An offset within the VBO if we want to.
5
GLsizei stride
The distance between elements within the VBO.
glVertexArrayAttribBinding
Parameter
Type
Description
1
GLuint vaobj
The VAO name.
2
GLuint attribindex
The shader attribute index.
3
GLuint bindingindex
The binding point.
glVertexArrayAttribFormat
Parameter
Type
Description
1
GLuint vaobj
The VAO name.
2
GLuint attribindex
The shader attribute index.
3
GLint size
The number of components
4
GLenum type
The type of the component.
5
GLboolean normalized
GL_TRUE integer values normalized to [-1, 1].GL_FALSE integer values converted directly to float values.
6
GLuint relativeoffset
The distance between elements within the buffer.
glVertexArrayBindingDivisor
Parameter
Type
Description
1
GLuint vaobj
The VAO name.
2
GLuint bindingindex
The binding point.
3
GLuint divisor
The divisor value.
glEnableVertexArrayAttrib
Parameter
Type
Description
1
GLuint vaobj
The VAO name.
2
GLuint index
The shader attribute to enable.