5
votes

I have a problem understanding association between VAO and buffer bound to GL_ELEMENT_ARRAY_BUFFER (let's call it EBO). I got to know that it is part of VAO state, but differ from buffers used along with glVertexAttribPointer calls (those buffers are simply remembered by VAO as attributes storage omitting need to bind them - if I understood correctly).
In this discussion it is claimed:

Unlike GL_ARRAY_BUFFER, a VAO store the current binding for GL_ELEMENT_ARRAY_BUFFER. Calling glBindBuffer(GL_ELEMENT_ARRAY_BUFFER) stores a reference to the specified buffer in the currently-bound VAO. glDrawElements() etc take the vertex indices from the buffer stored in the currently-bound VAO. So switching between VAOs switches between element arrays.

But do I need to call glBindBuffer(GL_ELEMENT_ARRAY_BUFFER) between bind and unbind of VAO to make sure it will 'save' it in its state or VAO will just take currently bound EBO when VAO gets created?
Also the answer quoted above isn't clear to me whether VAO just 'knows' (as attribute storage buffers) which buffer indices (glDrawElements) have to be taken from or does VAO binds proper EBO when VAO gets bound?

edit: First of my questions has been answered here, however I believe the second one was answered by @Rabbid76.

2

2 Answers

4
votes

Do I need to call glBindBuffer(GL_ELEMENT_ARRAY_BUFFER) between bind and unbind of VAO?

The OpenGL specification (chapter 10.3. VERTEX ARRAYS) clearly says:

A vertex array object is created by binding a name returned by GenVertexArrays with the command
void BindVertexArray( uint array ); array is the vertex array object name.
The resulting vertex array object is a new state vector, comprising all the state and with the same initial values listed in tables 23.3 and 23.4.
BindVertexArray may also be used to bind an existing vertex array object. If the bind is successful no change is made to the state of the bound vertex array object, and any previous binding is broken.

The Tables 23.3 and 23.4 contain ELEMENT_ARRAY_BUFFER_BINDING.

This means, that the GL_ELEMENT_ARRAY_BUFFER has to be bound after the vertex array object has been bound (glBindVertexArray).
The "name" of the GL_ELEMENT_ARRAY_BUFFER object is stored in the vertex array objects state vector.
If the vertex array object has been unbound and is bound again, then the GL_ELEMENT_ARRAY_BUFFER is known and bound again, too.


Note, glBufferData creates a new data store for a buffer object. glBufferData delete any existing data store, and set the values of the buffer object’s state variables. This means, that the data are associated to the buffer object until you associate new data. - see Khronos reference page glBufferData and OpenGL 4.6 API Compatibility Profile Specification; 6.1 Creating and Binding Buffer Objects

3
votes

If you set things up correctly, at draw time you should only be binding VAOs. That is sort of the whole point, avoid the CPU overhead of calling into the GL driver repeatedly for each piece of geometry.

During your initial setup you should create and bind a VAO, then bind all attribute buffers and describe them with glVertexAttribPointer, enable them with glEnableVertexAttribArray and lastly bind the GL_ELEMENT_ARRAY_BUFFER. After that, I would bind the VAO to null so you don't accidentally bind something else in the following lines.

(Note that the glBindBuffer of the attribute buffer itself is not directly recorded into the VAO, but rather inferred at the call site of glVertexAttribPointer. That is, whatever is currently bound to GL_ARRAY_BUFFER when you call glVertexAttribPointer will be what the VAO sources for vertex pulling.)

During your render loop you should bind the different VAOs you created earlier.

It's a little bit confusing because in practice sometimes binding a VAO means "I want to start recording a little macro" (at initial setup time) and sometimes binding a VAO means "I want you to play back all the bindings in that macro I recorded earlier" (at render time). It is described in the original RFC as:

   The currently bound vertex array object is used for all commands
which modify vertex array state, such as VertexAttribPointer and
EnableVertexAttribArray; all commands which draw from vertex arrays,
such as DrawArrays and DrawElements; and all queries of vertex
array state.

https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_vertex_array_object.txt

See also tables 6.4 and 6.5 in the GL standard to see exactly what fields are stored in the VAO struct:

https://www.khronos.org/registry/OpenGL/specs/gl/glspec32.core.pdf