“缓冲区绑定和属性关联 您可能会注意到,即使它是渲染属性设置的一部分,glBindBuffer(GL_ARRAY_BUFFER)也没有列在该列表中。与GL_ARRAY_BUFFER的绑定不是VAO的一部分,因为当您调用glBindBuffer(GL_ARRAY_BUFFER)时,缓冲对象与顶点属性之间的关联并没有发生。这种关联是在调用glVertexAttribPointer时发生的。 当您调用glVertexAttribPointer时,OpenGL会将此调用时绑定到GL_ARRAY_BUFFER的任何缓冲区与给定的顶点属性相关联。将GL_ARRAY_BUFFER绑定视为glVertexAttribPointer读取的全局指针。因此,您可以自由地绑定任何想要或完全不绑定到GL_ARRAY_BUFFER的内容,而不会影响最终渲染。因此,VAO确实存储了哪些缓冲区对象与哪些属性相关联;但是,它们不存储GL_ARRAY_BUFFER绑定本身。”
起初我错过了最后一行“但是,它们不存储GL_ARRAY_BUFFER绑定本身”。在注意到这一行之前,我认为一旦调用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());
经过一番搜索,我找到了之前遗漏的细节,并发现如果在绘制函数中在glBufferData之前调用glBindBuffer,一切都会正常工作。
我对于我的网格渲染一开始为什么能够正常工作感到困惑。难道只有在更改缓冲区数据时才需要再次调用glBindBuffer吗?或者如果不绑定缓冲区,行为是未定义的,我只是运气好让它起作用吗?
请注意,我针对的是OpenGL 3.0版本。