顶点数组对象-关于确切保存有关当前绑定的顶点缓冲区的状态信息的困惑 [英] Vertex Array Objects - Confusion regarding exactly what state information is saved about the currently bound vertex buffer

查看:118
本文介绍了顶点数组对象-关于确切保存有关当前绑定的顶点缓冲区的状态信息的困惑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建 arcynthesis 上的优秀教程,同时构建图形引擎和发现我对VAO的理解不如我想象的那样.

I'm working through the excellent tutorials at arcsynthesis while building a graphics engine and have discovered I don't understand VAOs as much as I thought I had.

从教程第5章.深度对象

缓冲区绑定和属性关联

Buffer Binding and Attribute Association

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

You may notice that glBindBuffer(GL_ARRAY_BUFFER) is not on that list, even though it is part of the attribute setup for rendering. The binding to GL_ARRAY_BUFFER is not part of a VAO because the association between a buffer object and a vertex attribute does not happen when you call glBindBuffer(GL_ARRAY_BUFFER). This association happens when you call glVertexAttribPointer.

当您调用glVertexAttribPointer时,OpenGL会在此调用时获取绑定到GL_ARRAY_BUFFER的任何缓冲区,并将其与给定的vertex属性相关联.将GL_ARRAY_BUFFER绑定视为glVertexAttribPointer读取的全局指针.因此,在调用glVertexAttribPointer调用之后,您可以随意将任何所需的内容或根本不绑定的内容绑定到GL_ARRAY_BUFFER.在最终渲染中不会有任何影响.因此,VAO确实存储了哪些缓冲区对象与哪些属性相关联.但它们本身不存储GL_ARRAY_BUFFER绑定.

When you call glVertexAttribPointer, OpenGL takes whatever buffer is at the moment of this call bound to GL_ARRAY_BUFFER and associates it with the given vertex attribute. Think of the GL_ARRAY_BUFFER binding as a global pointer that glVertexAttribPointer reads. So you are free to bind whatever you want or nothing at all to GL_ARRAY_BUFFER after making a glVertexAttribPointer call; it will affect nothing in the final rendering. So VAOs do store which buffer objects are associated with which attributes; but they do not store the GL_ARRAY_BUFFER binding itself.

我最初错过了最后一行"...但是它们不存储GL_ARRAY_BUFFER绑定本身".在我注意到这一行之前,我认为一旦调用glVertexAttribPointer,就会保存当前绑定的缓冲区.缺少这些知识,我建立了一个网格类,并且能够获得具有正确渲染多个网格的场景.

I initially missed the last line "...but they do not store the GL_ARRAY_BUFFER binding itself". Before I noticed this line I thought that the currently bound buffer was saved once glVertexAttribPointer was called. Missing this knowledge, I built a mesh class and was able to get a scene with a number of meshes rendering properly.

该代码的一部分在下面列出.请注意,我不会在绘图函数中调用glBindBuffer.

A portion of that code is listed 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());

现在我要开始照明了,我想获得一些调试图纸,以便可以验证所有法线是否正确.目前,我只是将要渲染一帧的所有线条存储在矢量中.由于此数据可能会在每一帧发生变化,因此我正在使用GL_DYNAMIC_DRAW并在渲染之前指定数据.

Now that I'm about to start lighting I wanted to get some debug drawing up so I could verify all my normals are correct. Currently I just store all lines to be rendered for a frame in a vector. Since this data will likely change every frame, I'm using GL_DYNAMIC_DRAW and specify the data right before I render it.

最初,当我这样做时,我会得到一些垃圾线,它们会指向无穷大.令人反感的代码如下:

Initially when I did this I would get garbage lines that would just point off into infinity. The offending code is 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());

经过一番摸索,以及发现上面错过的细节,我发现,如果在draw函数中的glBufferData之前调用glBindBuffer,则一切正常.

After a bit of hunting, as well as finding the detail I missed above, I found that if I call glBindBuffer before glBufferData in the draw function, everything works out fine.

鉴于这个原因,我对为什么我的网格渲染首先起作用感到困惑.如果更改缓冲区中的数据,是否仅需要再次调用glBindBuffer?或者,如果您不绑定缓冲区,而我却很不幸并能正常工作,行为是否未定义?

I'm confused as to why my mesh rendering worked in the first place given this. Do I only need to call glBindBuffer again if I change the data in the buffer? Or is behavior undefined if you don't bind the buffer and I was just unlucky and had it work?

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

推荐答案

如果我更改了 缓冲?

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

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

Yes, The VAO object remembers which buffers were bound each time you called glVertexAttribPointer whilst that VAO was bound, so you don't usually need to call glBindBuffer again. If you want to change the data in the buffer however, OpenGL needs to know which buffer you are changing, so you need to call glBindBuffer before calling glBufferData. It is irrelevant which VAO object is bound at this point.

这篇关于顶点数组对象-关于确切保存有关当前绑定的顶点缓冲区的状态信息的困惑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆