当前位置: 首页 > 知识库问答 >
问题:

顶点数组对象-关于当前绑定的顶点缓冲区到底保存了什么状态信息的混淆

法浩壤
2023-03-14

在构建图形引擎时,我正在通过arcsynthesis的优秀教程,发现我对VAOs的理解并不像我想象的那样多。

从教程第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;它不会影响最终渲染中的任何内容。所以VAOs确实存储哪些缓冲区对象与哪些属性相关联;但是它们不存储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());

经过一番搜索,并找到了上面遗漏的细节,我发现如果在draw函数中调用glBindBuffer之前调用glBufferData,一切都很好。

我很困惑为什么我的网格渲染在一开始就工作了。如果更改缓冲区中的数据,我是否只需要再次调用glBindBuffer?或者,如果您不绑定缓冲区,而我只是运气不好,让它工作了,行为是不定义的?

请注意,我的目标是OpenGL3.0版本。

共有1个答案

伏砚
2023-03-14

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

是的,当您每次调用glvertexattribpointer时,VAO对象都会记得绑定了哪些缓冲区,因此通常不需要再次调用glbindbuffer。但是,如果要更改缓冲区中的数据,OpenGL需要知道您正在更改哪个缓冲区,因此在调用glbindbufferdata之前需要调用glbufferdata。在这一点上绑定哪个VAO对象是无关紧要的。

 类似资料:
  • 我正在努力理解这两个,如何使用它们,以及它们是如何联系的。假设我想创建一个简单的地形和一个有纹理的立方体。对于这两个对象,我有三角形、顶点的数组,对于立方体,我有一个包含纹理数据的数组。我的问题是:我如何使用VAOs和VBOs来创建和呈现这两个? null

  • 下面的lwjgl3代码设置缓冲区等,用于呈现三角形。我能看到三角形。现在我正努力弄明白到底是怎么回事。 下面是我对代码的理解。我们首先创建一个顶点缓冲区对象,它只是一个数组的容器。glBindBuffer()和glBufferData()使用顶点数组填充顶点缓冲区对象。我们再次对第二个顶点数组执行此操作。然后我们编译顶点和片段着色器,并将它们添加到着色器程序中。不知怎么的,这个程序访问第二个顶点缓

  • 我正在尝试从ArrayList读取并创建VBO,然后对其进行渲染。问题是我只是渲染了一个空白屏幕。当我立即渲染时,一切都很好;只有现在VBO的才不起作用。 游戏循环如下所示,相机调用glTranslate和glRotate函数。 渲染方法: 阵列列表具有顶点和链接的颜色。每个体素将其顶点添加到ArrayList(而不是立即渲染)。

  • 我目前正在使用LWJGL / OpenGL创建一个2D,自上而下的游戏,但是在绘制实体之后,在使用顶点缓冲区对象渲染实体后,在让它们四处移动的过程中,我遇到了一些问题。这是渲染线程的 run() 方法,以及设置方法: 实体从抽象超类继承这些方法来设置 VBO 并绘制实体(呈现线程中的 drawEntities 方法仅调用该方法,实体更新方法(见下文),而 setUpEntities 调用 setU

  • 我正在努力学习LWJGL (OpenGL)不得不说我很艰难。 我试着在窗户上画一个三角形和一个四边形,最后我设法做到了。 但我还有一个问题 如果您觉得这个问题很愚蠢,请提前表示歉意,但我在网上找不到非常详细的教程,所以很难理解,因为这是我第一次使用OpenGL。 话虽如此,这是代码的相关部分: 假设程序以60 fps的速度运行。< br >这意味着渲染方法每秒钟被游戏循环调用60次。 该渲染方法的

  • 我想知道什么等效的和帧缓冲区对象(FBO)。是否存在等价物,或者我需要自己实现一些东西?