Pet*_*ark 9 opengl vertex-buffer vertex-array-object
我在构建图形引擎时正在研究arcsynthesis的优秀教程,并发现我不像我想象的那样理解VAO.
从教程第5章深入的对象
缓冲区绑定和属性关联
您可能会注意到glBindBuffer(GL_ARRAY_BUFFER)不在该列表中,即使它是用于渲染的属性设置的一部分.对GL_ARRAY_BUFFER的绑定不是VAO的一部分,因为当调用glBindBuffer(GL_ARRAY_BUFFER)时,缓冲区对象和顶点属性之间的关联不会发生.调用glVertexAttribPointer时会发生此关联.
当您调用glVertexAttribPointer时,OpenGL会将此调用时的任何缓冲区绑定到GL_ARRAY_BUFFER,并将其与给定的顶点属性相关联.将GL_ARRAY_BUFFER绑定视为glVertexAttribPointer读取的全局指针.因此,在进行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());
Run Code Online (Sandbox Code Playgroud)
现在我即将开始照明,我想得到一些调试,所以我可以验证我的所有法线都是正确的.目前我只存储要在向量中为帧渲染的所有行.由于这些数据可能会在每一帧都发生变化,因此我使用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());
Run Code Online (Sandbox Code Playgroud)
经过一些狩猎,以及找到我错过的细节,我发现如果我在绘制函数中调用glBufferData之前的glBindBuffer,一切都很好.
我很困惑为什么我的网格渲染在第一个地方起作用了.如果我更改缓冲区中的数据,是否只需要再次调用glBindBuffer?或者如果你没有绑定缓冲区,行为是未定义的,我只是运气不好而且有效吗?
请注意,我的目标是OpenGL 3.0版.
Guy*_*yRT 11
如果我更改缓冲区中的数据,是否只需要再次调用glBindBuffer?
是的,VAO对象会记住每次glVertexAttribPointer在VAO绑定时调用时绑定的缓冲区,因此通常不需要glBindBuffer再次调用.但是,如果要更改缓冲区中的数据,OpenGL需要知道要更改的缓冲区,因此需要在调用glBindBuffer之前调用glBufferData.此时VAO对象被绑定是无关紧要的.
| 归档时间: |
|
| 查看次数: |
3134 次 |
| 最近记录: |