Use of Vertex Array Objects and Vertex Buffer Objects

ali picture ali · Apr 26, 2014 · Viewed 17.5k times · Source

I am trying to understand these two, how to use them and how they are related. Let's say I want to create a simple terrain and a textured cube. For both objects I have the array of triangles vertices and for the cube I have an array containing the texture's data. My question is: how do I use VAOs and VBOs to create and render these two?

  1. Would I have to create a VAO and VBO for each object?
  2. or should create a VAO for each object's VBO (vertices, texture data, etc.)?

There are many tutorials and books but I still don't get the very idea of how these concepts must be understood and used.

Answer

Andon M. Coleman picture Andon M. Coleman · Apr 26, 2014

Fundamentally, you need to understand two things:

  1. Vertex Array Objects (VAOs) are conceptually nothing but thin state wrappers.

  2. Vertex Buffer Objects (VBOs) store actual data.

Another way of thinking about this is that VAOs describe the data stored in one or more VBOs.

Think of VBOs (and buffer objects in general) as unstructured arrays of data stored in server (GPU) memory. You can layout your vertex data in multiple arrays if you want, or you can pack them into a single array. In either case, buffer objects boil down to locations where you will store data.

Vertex Array Objects track the actual pointers to VBO memory needed for draw commands.

They are a little bit more sophisticated than pointers as you would know them in a language like C, however. Vertex pointers keep track of the buffer object that was bound when they were specified, the offset into its address space, stride between vertex attributes and how to interpret the underlying data (e.g. whether to keep integer values or to convert them to floating-point [0.0,1.0] by normalizing to the data type's range).

For example, integer data is usually converted to floating-point, but it is the command you use to specify the vertex pointer (glVertexAttribPointer (...) vs. glVertexAttribIPointer (...)) that determines this behavior.

Vertex Array Objects also track the buffer object currently bound to GL_ELEMENT_ARRAY_BUFFER.

GL_ELEMENT_ARRAY_BUFFER is where the command: glDrawElements (...) sources its list of indices from (assuming a non-zero binding) and there is no glElementArrayPointer (...) command. glDrawElements (...) combines the pointer and draw command into a single operation, and will use the binding stored in the active Vertex Array Object to accomplish this.


With that out of the way, unless your objects share vertex data you are generally going to need a unique set of VBOs for each.

You can use a single VAO for your entire software if you want, or you can take advantage of the fact that changing the bound VAO changes nearly the entire set of states necessary to draw different objects.

Thus, drawing your terrain and cube could be as simple as changing the bound VAO. You may have to do more than that if you need to apply different textures to each of them, but the VAO takes care of all vertex data related setup.