Use of Vertex Array Objects and Vertex Buffer Objects
Asked Answered
M

2

50

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.

Manicure answered 26/4, 2014 at 18:15 Comment(0)
I
85

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.

Illa answered 26/4, 2014 at 19:4 Comment(1)
Thanks so much. Now I understand what VAO and VBO are exactly. It looks like I must have a good and clear overview of the 3D objects I want to create then choose the best way of using VAOs and VBOs to save memory and CPU/GPU time.Manicure
M
8

Your question is not easily answerable here, but rather in a tutorial. You probably already know these two websites, but if not, I'm leaving the references.

OGLDEV

OpenGL-Tutorial.org

Now trying to elucidate your questions, a Vertex Array Object is an OpenGL object designed with the goal of reducing API overhead for draw calls. You can think of it as a container for a Vertex Buffer and its associated states. Something similar perhaps to the old display-lists. Normally, there is a 1 to 1 relationship between a VAO and a VBO; that is, each VAO contains a unique VBO. But this is not strictly necessary. You could have several VAOs referencing the same VBO.

The simplest way to model this in code, I think, would be for you to have a VAO class/type and a method to attach a VBO to it. Then give an instance of VAO to each mesh. The mesh in turn can have a reference to a VBO type that may be its own or a shared one.

Mastoiditis answered 26/4, 2014 at 19:6 Comment(5)
Thanks. I visited those links but I will have a look at them once more, now that I understand things betterManicure
Having a VAO for each VBO would be horribly inefficient though, since you'd have a VAO to bind to prior to each draw call.Thorbert
@Stradigos, I don't see how that would be less efficient than binding a VBO+IBO before each draw call. With the VAO you need way less API calls to set the drawing context.Mastoiditis
Profile, of course, but see this thread: https://mcmap.net/q/355623/-opengl-how-many-vaos EDIT: Pretty sure I read it on OpenGL's site a while back too. Can't find it now though.Thorbert
@Stradigos, from the answer you've linked: "Personally I tend to use one VBO and VAO per layout, i.e. if my data is made up of an equal number of attributes with the same properties, I put them into a single VBO and a single VAO." - that's exactly how I'd do ;) apologies if my answer passed a different understanding.Mastoiditis

© 2022 - 2024 — McMap. All rights reserved.