Vertex array objects - confusion as to what state information is stored in the current linked vertex buffer

I am working on great arcsynthesis tutorials on creating a graphics engine and found that I don't understand VAOs as much as I thought.

From the textbook Chapter 5. Objects in depth

Association of buffer bindings and attributes

You may notice that glBindBuffer (GL_ARRAY_BUFFER) is not on this list, although it is part of setting the attribute for rendering. The binding to GL_ARRAY_BUFFER is not part of the VAO because the connection between the buffer object and the vertex attribute does not occur when you call glBindBuffer (GL_ARRAY_BUFFER). This association occurs when you call glVertexAttribPointer.

When you call glVertexAttribPointer, OpenGL takes any buffer at the time of the call associated with GL_ARRAY_BUFFER and associates it with the specified vertex attribute. Think of binding GL_ARRAY_BUFFER as a global pointer that glVertexAttribPointer reads. This way you can bind whatever you want, or do nothing at all with GL_ARRAY_BUFFER after calling glVertexAttribPointer; this will not affect the final rendering. In this way, VAOs store which buffer objects are associated with attributes; but they do not retain the GL_ARRAY_BUFFER binding.

First I skipped the last line "... but they don’t keep the GL_ARRAY_BUFFER binding." Before I noticed this line, I thought that the buffer currently bound was saved after calling glVertexAttribPointer. Without this knowledge, I built a mesh class and was able to get a scene with a certain amount of mesh rendering.

Part of this code is given below. Note that I do not call glBindBuffer in the draw function.

// MESH RENDERING /* ... */ /* SETUP FUNCTION */ /* ... */ // Setup vertex array object glGenVertexArrays(1, &_vertex_array_object_id); glBindVertexArray(_vertex_array_object_id); // Setup vertex buffers glGenBuffers(1, &_vertex_buffer_object_id); glBindBuffer(GL_ARRAY_BUFFER, _vertex_buffer_object_id); glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(vertex), &_vertices[0], GL_STATIC_DRAW); // Setup vertex attributes glEnableVertexAttribArray(e_aid_position); glEnableVertexAttribArray(e_aid_normal); glEnableVertexAttribArray(e_aid_color); glEnableVertexAttribArray(e_aid_tex); glVertexAttribPointer(e_aid_position, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, pos)); glVertexAttribPointer(e_aid_normal, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, norm)); glVertexAttribPointer(e_aid_color, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, col)); glVertexAttribPointer(e_aid_tex, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, tex)); /* ... */ /* DRAW FUNCTION */ /* ... */ glBindVertexArray(_vertex_array_object_id); glDrawArrays(GL_TRIANGLES, 0, _vertices.size()); 

Now that I am about to start lighting, I wanted to get debugging so that I can check if all my normals are correct. Currently, I just keep all the lines that will be displayed for the frame in the vector. Since this data is likely to change every frame, I use GL_DYNAMIC_DRAW and set the data right before I process it.

Initially, when I did this, I got garbage lines that would simply indicate infinity. Violation code below:

 // DEBUG DRAW LINE RENDERING /* ... */ /* SETUP FUNCTION */ /* ... */ // Setup vertex array object glGenVertexArrays(1, &_vertex_array_object_id); glBindVertexArray(_vertex_array_object_id); // Setup vertex buffers glGenBuffers(1, &_vertex_buffer_object_id); glBindBuffer(GL_ARRAY_BUFFER, _vertex_buffer_object_id); // Note: no buffer data supplied here!!! // Setup vertex attributes glEnableVertexAttribArray(e_aid_position); glEnableVertexAttribArray(e_aid_color); glVertexAttribPointer(e_aid_position, 3, GL_FLOAT, GL_FALSE, sizeof(line_vertex), (GLvoid*)offsetof(line_vertex, pos)); glVertexAttribPointer(e_aid_color, 4, GL_FLOAT, GL_FALSE, sizeof(line_vertex), (GLvoid*)offsetof(line_vertex, col)); /* ... */ /* DRAW FUNCTION */ /* ... */ glBindVertexArray(_vertex_array_object_id); // Specifying buffer data here instead!!! glBufferData(GL_ARRAY_BUFFER, _line_vertices.size() * sizeof(line_vertex), &_line_vertices[0], GL_DYNAMIC_DRAW); glDrawArrays(GL_LINES, 0, _line_vertices.size()); 

After a little hunting, as well as searching for the details that I skipped above, I found that if I call glBindBuffer before glBufferData in the draw function, everything will be fine.

I am confused by why my mesh rendering worked primarily with this in mind. Do I need to call glBindBuffer again if I change the data in the buffer? Or undefined behavior if you don't bind the buffer and I just got out of luck and did it work?

Please note that I am targeting OpenGL version 3.0.

+7
source share
1 answer

Do I need to call glBindBuffer again if I change the data to the buffer?

Yes, the VAO object remembers which buffers were bound every time you called glVertexAttribPointer , while the VAO was bound, so you usually don't need to call glBindBuffer again. If you want to change the data in the buffer, OpenGL needs to know which buffer you are changing, so you need to call glBindBuffer before calling glBufferData . It does not matter which VAO object is connected at this point.

+10
source

All Articles