Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGL, VAOs and multiple buffers

Tags:

opengl

I am writing a little graphics engine using OpenGL ( via OpenTK with C# ).

To define vertex attributes, I have a VertexDeclaration class with an array of VertexElement structures that are mapped to glEnableVertexAttribArray/glVertexAttribPointer calls.

Also, to support multiple vertex streams, I have a special structure holding a vertex buffer, vertex declaration, vertex offset and instance frequency (like the XNA's VertexBufferBinding structure).

Currently, whenever a drawing call is invoked, I iterate over all the set vertex streams and bind their vertex buffers, apply vertex declarations, disable unused vertex attributes and draw the primitives.

I would like to use VAOs to cache the glEnableVertexAttribArray calls into them, and whenever a vertex stream is applied, bind the VAO and change its array buffer binding.

Is that a correct usage of VAOs?

like image 319
Luna Inverse Avatar asked Jan 10 '13 01:01

Luna Inverse


People also ask

Can a VAO have multiple VBOS?

Yes, VAO state includes vertex attribute specification for multiple attributes. Each attribute has its own format information and can come from a distinct buffer object.

What are OpenGL buffers?

Buffer Objects are OpenGL Objects that store an array of unformatted memory allocated by the OpenGL context (AKA the GPU). These can be used to store vertex data, pixel data retrieved from images or the framebuffer, and a variety of other things.

What is a vertex buffer in OpenGL?

A vertex buffer object (VBO) is an OpenGL feature that provides methods for uploading vertex data (position, normal vector, color, etc.) to the video device for non-immediate-mode rendering.

What is glEnableVertexAttribArray?

Description. glEnableVertexAttribArray enables the generic vertex attribute array specified by index . glDisableVertexAttribArray disables the generic vertex attribute array specified by index . By default, all client-side capabilities are disabled, including all generic vertex attribute arrays.


1 Answers

Is that a correct usage of VAOs?

No1.

glVertexAttribPointer uses the buffer object that was bound to GL_ARRAY_BUFFER at the moment the function was called. So you can't do this:

glVertexAttribPointer(...); glBindBuffer(GL_ARRAY_BUFFER, bufferObject); glDrawArrays(...); 

This will not use bufferObject; it will use whatever was bound to GL_ARRAY_BUFFER when glVertexAttribPointer was originally called.

VAOs capture this state. So the VAO will, for each vertex attribute, store whatever buffer object was bound to GL_ARRAY_BUFFER when it was called. This allows you to do things like this:

glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, buffer1); glVertexAttribPointer(0, ...); glVertexAttribPointer(1, ...); glBindBuffer(GL_ARRAY_BUFFER, buffer2); glVertexAttribPointer(2, ...); 

Attributes 0 and 1 will come from buffer1, and attribute 2 will come from buffer2. VAO now captures all of that state. To render, you just do this:

glBindVertexArray(VAO); glDraw*(); 

In short, if you want to change where an attribute's storage comes from in OpenGL, you must also change it's format. Even if it's the same format, you must call glVertexAttribPointer again.

1: This discussion assumes you're not using the new ARB_vertex_attrib_binding. Or, as it is otherwise known, "Exactly how Direct3D does vertex attribute binding." If you happen to be using an implementation that offers this extension, you can effectively do what you're talking about, because the attribute format is not tied with the buffer object's storage. Also, the tortured logic of glVertexAttribPointer is gone.

In general, the way we solve this in the OpenGL world is to put as many things as possible in the same buffer object. Failing that, just use one VAO for each object.

like image 55
Nicol Bolas Avatar answered Sep 17 '22 15:09

Nicol Bolas