Open GL : Using Vertex Array Objects to Organize Your Buffers

9/9/2012 9:42:26 PM

You just read about vertex buffer objects. Each vertex attribute has an offset within a buffer and a set of other state such as data type and stride. Each one also has an associated buffer, which can be different for each attribute. Calling glVertexAttribPointer sets all of this state, including the buffer binding for the attribute. If you have a fairly complex scene with several objects in it and each object keeps its vertex data in its own VBO, then that is a reasonable amount of state per object. If the application is well-written, drawing one of these object may end up as simple as a single call to a function like glDrawElements or glDrawArrays.

Even if the layout of data is the same between objects (it probably will be for many applications) and the offsets of the data are the same (maybe all data starts at offset zero, for example), it is still necessary to call glVertexAttribPointer for every vertex attribute. For an object that has, say, eight vertex attributes, this means at least one call to glBindBuffer (possibly up to eight if all the vertex attributes are in separate buffer objects), and eight calls to glVertexAttribPointer. If you’re using indexed vertices, you also need to bind your GL_ELEMENT_ARRAY_BUFFER. All this to prepare for a single call to glDrawElements. This is a lot of state to set, a lot of error checking that the driver has to do, and a lot of information that the application has to look after.

To help organize all this information, OpenGL provides an object called a vertex array object (VAO). A VAO is a container that packages together all of the state that can be set by glVertexAttribPointer and a few other functions. When using a VAO, all state specified through a call to glVertexAttribPointer is stored in the current VAO. There is no default VAO in OpenGL. This means that before you can even specify your vertex pointers, you need to create and bind a VAO. For simple applications, it may be sufficient to create a single VAO, bind it, and leave it bound for the lifetime of the application (as we did when we introduced VBOs earlier). However, an application can create as many VAOs as it needs and use them to manage all of the array state. When it’s time to draw using a particular set of vertex attributes, simply bind the VAO containing that set of state and start drawing. This allows each object in a scene to manage its own vertex buffers by creating a VAO to maintain its state and binding it before drawing. That way, the object won’t upset the vertex array state of any other object in the scene.

To create one or more VAOs, call

void glGenVertexArrays(GLsizei n, GLuint *arrays);

Like most other OpenGL objects, VAOs are referred to by name represented as unsigned integers. The glGenVertexArrays function creates n vertex arrays and places their names in the array arrays. If glGenVertexArrays fails to allocate a VAO for some reason, it returns zero for its name. A well-written application should always check for this condition before trying to use the result. Like buffer objects, the VAO name zero is reserved by OpenGL to mean “no VAO.” Again, when no VAO is bound, glVertexAttribPointer will not work and will generate an error if you call it. To delete VAOs, call

void glDeleteVertexArrays(GLsizei n, GLuint *arrays);

This function deletes the n VAOs whose names are in arrays. It is important for your application to clean up after itself. If arrays has an element containing the name zero, that will be ignored. This means that you can safely pass an array previously written to by glGenVertexArrays to glDeleteVertexArrays without worrying whether some of the names might be zero (due to an error during the execution of glGenVertexArrays, for example). To start using a VAO, call

void glBindVertexArray(GLuint array);

This makes array the current VAO. When a new VAO is bound for the first time, it contains all of the default state that would be present in a freshly created context. From now on, any time you call a function that accesses the vertex array state, it will access the state contained in the currently bound VAO. This includes functions that set state, such as glVertexAttribPointer; functions that implicitly use that state, such as glDrawArrays or glDrawElements; and functions that explicitly read vertex array state, such as glGetIntegerv.

Now that we have a VAO, we can set as much state on it as we like. We can call glVertexAttribPointer as many times as we need and the state will be stored in the VAO. If we call glBindBuffer followed by glVertexAttribPointer, the buffer binding will also be stored in the VAO. Note, though, that while the buffer binding associated with the vertex attribute is stored in the VAO, binding a new VAO does not change the current buffer bindings. That is, the actual state of the currently bound buffers is not stored in the VAO. To return to the example at the start of this section—the object with many vertex attributes, each with different state and buffer bindings—we can improve the performance of this greatly using VAOs.

Instead of calling glBindBuffer and glVertexAttribPointer many times right before drawing the object, we can do it at initialization time. When it is created, the object can generate a VAO, bind it using glBindVertexArray, and set all of its vertex array state as if it were about to render itself. After initialization, return OpenGL to having no VAO bound by calling


Now, when the object is about to be rendered, call glBindVertexArray again with the object’s VAO, and then call the rendering functions such as glDrawArrays. Thus, rendering a complete object that has many vertex attributes, all stored in a collection of VBOs with different parameters, can be as simple as two function calls—glBindVertexArray and glDrawElements, for example. This is also beneficial for layered libraries, scene graph managers, and middleware that might want to render without disturbing the current OpenGL state. If the normal behavior of the environment is to have no VAO bound, then each object binds its own VAO, renders itself, and then binds VAO zero, resetting everything.

Most View
Sony New Waterproof Player
PowerShell for Microsoft SharePoint 2010 : Flow Control and Object Disposal - Flow-Control Cmdlets
Lian Li PC-V335 - Nice And Attractive Chassis
HTC Butterfly - Quad Damage
Microsoft Lync Server 2010 : Microsoft Communicator Client for Macintosh - Getting Around in the Client
Sharepoint 2013 : Restore an Earlier Version of a File or List Item, Approve or Reject a File or List Item
Upgrading and Converting to Access 2010 : TO CONVERT OR TO ENABLE
USB DACs Super Test: PC + DAC = HI-FI (Part 1)
Windows Server 2003 : Domain Name System - Zones Versus Domains, Resource Records
Asus Transformer Book Detachable Ultrabook Review (Part 4)
Top 10
Return Of The Mac McIntosh MXA70 Review (Part 2)
Return Of The Mac McIntosh MXA70 Review (Part 1)
SMC Pentax-DA 18–135mm f/3.5-5.6ED AL (IF) DC WR All-Weather Friend
Sony Cyber-Shot DSC-RX100 III Perfecting The Threequel
Porsche 911 GT3 (996) Review
Porsche 911T (1967 SWB) Review
The Volkswagen Polo 1.5 TDI – Offer Effortless Performance In All Situations (Part 2)
The Volkswagen Polo 1.5 TDI – Offer Effortless Performance In All Situations (Part 1)
The Rolls-Royce Wraith – A Car Of Considerable Allure And Significance
Twin Test – New BMW M3 vs Porsche Macan – Brawn To Be Wild (Part 3)