MULTIMEDIA

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

glBindVertexArray(0);

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.

Other  
 
Most View
Windows Server 2008 and Windows Vista : Benefits of Group Policy Preferences (part 2) - Working with Any Organizational Unit Design
LG Nexus 4 – Google’s Favorite Child (Part 2)
Windows Server 2008 and Windows Vista : Group Policy Management Console Delegation - Modeling GPOs, RSoP of GPOs
Apple - Celebrating 7 Years Of Success
SQL Server 2012 : SQL Server Management and Development Tools - Object Explorer (part 1)
Qooq - The First Culinary Tablet Made For The Kitchen
HP Photosmart 7520 e-All-in-One
Gigabyte GA-Z77-D3H Mainboard - Not So Complicated LGA 115 Mainboard (Part 3)
Canon EOS M - Live Up To Its Pedigree?
New Products For March 2013 (Part 1)
Top 10
Sharepoint 2013 : Farm Management - Disable a Timer Job,Start a Timer Job, Set the Schedule for a Timer Job
Sharepoint 2013 : Farm Management - Display Available Timer Jobs on the Farm, Get a Specific Timer Job, Enable a Timer Job
Sharepoint 2013 : Farm Management - Review Workflow Configuration Settings,Modify Workflow Configuration Settings
Sharepoint 2013 : Farm Management - Review SharePoint Designer Settings, Configure SharePoint Designer Settings
Sharepoint 2013 : Farm Management - Remove a Managed Path, Merge Log Files, End the Current Log File
SQL Server 2012 : Policy Based Management - Evaluating Policies
SQL Server 2012 : Defining Policies (part 3) - Creating Policies
SQL Server 2012 : Defining Policies (part 2) - Conditions
SQL Server 2012 : Defining Policies (part 1) - Management Facets
Microsoft Exchange Server 2010 : Configuring Anti-Spam and Message Filtering Options (part 4) - Preventing Internal Servers from Being Filtered