Opengl 顶点数组对象-关于当前绑定的顶点缓冲区究竟保存了哪些状态信息的混淆

Opengl 顶点数组对象-关于当前绑定的顶点缓冲区究竟保存了哪些状态信息的混淆,opengl,vertex-buffer,vertex-array-object,Opengl,Vertex Buffer,Vertex Array Object,在构建图形引擎的同时,我正在学习中的优秀教程,发现我对VAOs的理解不如我想象的那么多 来自教程 缓冲区绑定和属性关联 您可能会注意到,glBindBuffer(GL_ARRAY_BUFFER)不在该列表中,即使它是用于渲染的属性设置的一部分。绑定到GL_ARRAY_BUFFER不是VAO的一部分,因为在调用glBindBuffer(GL_ARRAY_BUFFER)时,缓冲区对象和顶点属性之间不会发生关联。调用glVertexAttributePointer时会发生此关联 调用GLVertexA

在构建图形引擎的同时,我正在学习中的优秀教程,发现我对VAOs的理解不如我想象的那么多

来自教程

缓冲区绑定和属性关联

您可能会注意到,glBindBuffer(GL_ARRAY_BUFFER)不在该列表中,即使它是用于渲染的属性设置的一部分。绑定到GL_ARRAY_BUFFER不是VAO的一部分,因为在调用glBindBuffer(GL_ARRAY_BUFFER)时,缓冲区对象和顶点属性之间不会发生关联。调用glVertexAttributePointer时会发生此关联

调用GLVertexAttributePointer时,OpenGL会将调用时绑定到GL_ARRAY_buffer的缓冲区与给定的顶点属性相关联。将GL_数组_缓冲区绑定视为glvertexattributepointer读取的全局指针。因此,在进行glvertexattributepointer调用后,您可以自由地将任何需要的内容绑定到GL_ARRAY_缓冲区,或者什么都不绑定;它不会影响最终渲染中的任何内容。所以VAO存储哪些缓冲区对象与哪些属性相关联;但它们不存储GL_数组_缓冲区绑定本身

我最初错过了最后一行“……但它们不存储GL_数组_缓冲区绑定本身”。在我注意到这一行之前,我认为当前绑定的缓冲区在调用glVertexAttribPointer后被保存。由于缺少这些知识,我构建了一个网格类,并且能够正确地获得具有多个网格渲染的场景

下面列出了该代码的一部分。注意,我没有在draw函数中调用glBindBuffer

// 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());
现在,我即将开始照明,我想得到一些调试图纸,以便我可以验证我的所有法线是正确的。目前,我只是将一帧要渲染的所有线存储在一个向量中。由于这些数据可能会改变每一帧,所以我使用GL_DYNAMIC_DRAW并在渲染之前指定数据

起初,当我这样做的时候,我会得到垃圾线,它会指向无穷远。违规代码如下:

// 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());
经过一番研究,并找到了上面遗漏的细节,我发现如果我在draw函数中调用glBindBuffer,在调用glBufferData之前调用glBindBuffer,一切都会顺利进行

考虑到这一点,我不明白为什么我的网格渲染一开始就可以工作。如果我更改缓冲区中的数据,是否只需要再次调用glBindBuffer?或者,如果您不绑定缓冲区,而我只是运气不好,让它工作,那么行为是否未定义

请注意,我的目标是OpenGL 3.0版。

如果我更改了中的数据,是否只需要再次调用glBindBuffer 缓冲区


是的,VAO对象会记住在绑定VAO时每次调用
glvertexattributepointer
时绑定的缓冲区,因此通常不需要再次调用
glBindBuffer
。但是,如果要更改缓冲区中的数据,OpenGL需要知道要更改的缓冲区,因此需要在调用
glBufferData
之前调用
glBindBuffer
。此时绑定哪个VAO对象无关紧要。

好的,这更有意义。我有一个小细节,我仍然有点模糊。假设我用VAO 1调用glBindVertexArray,它记住在调用GLVertexAttributePointer时VBO 1被绑定。然后我用VBO 2调用glBindBuffer,后跟GLDrawArray。应该使用哪个缓冲区,VBO 1还是VBO 2?我不相信这是人们通常会做的事情,我只是想确保我了解发生了什么。将使用VBO 1。请注意,无论您是否使用VAOs,这都是正确的。此外,在绑定VAO时,您可能绑定了多个VBO(每个属性可能有一个不同的绑定)。一旦您调用了glvertexattributepointer,那么此时将使用缓冲区绑定。太棒了,很高兴知道!非常感谢您的澄清!OpenGL仍然让我很困惑。当
VAO
被绑定时,
VBO
何时“附加”到
VAO
?调用
glGenBuffers
glBindBuffers
?(当然,
VAO
当前已绑定)。