【问题标题】:Does a VAO remember both a EBO/IBO (elements or indices) and a VBO?VAO 是否同时记住 EBO/IBO(元素或索引)和 VBO?
【发布时间】:2013-06-27 00:28:28
【问题描述】:

我的代码运行正常,但这可能是巧合,我不想稍后再纠缠于错误,所以我尽量保持它的整洁:

我执行以下操作来初始化网格:

  1. 生成并绑定 VBO 和缓冲区数据
  2. 生成和绑定 IBO 和缓冲区数据
  3. 生成和绑定 VAO
  4. 绑定与之前相同的 VBO,在 1 中生成。
  5. 启用我需要的顶点属性数组并设置顶点属性指针
  6. 再次绑定 IBO(不知道为什么)
  7. BindVertexArray 回到 0,这样我就不会弄乱我刚刚创建的 VAO

据我了解,VAO 将存储我启用的顶点属性数组的状态。它还将存储我绑定的 VBO 和 IBO。由于我通过将顶点数组绑定回 0 “关闭”了 VAO 上的所有操作,因此我确保没有其他代码会弄乱我的 VAO。所以如果这没问题,我只需要渲染:

  1. 绑定 VAO
  2. 绘制元素
  3. 解除绑定 VAO(绑定到 0)

这应该带来 AttribArray 状态以及存储的 VBO 和 IBO。我的问题是:

A. 设置 VertexAttribPointers 后是否需要绑定 IBO?如果有,为什么?

B. VAO 是否真的存储 VBO IBO?我听说它只存储绑定的 last 缓冲区,这意味着我必须像这样渲染:

  1. 绑定 VAO
  2. 绑定 VBO
  3. 绘制元素
  4. 解除绑定 VAO

但这没有任何意义,为什么在不存储两个缓冲区对象的情况下使用 VAO?不就是绑定 VBO 和 IBO,然后绘制元素而不绑定 VAO 一样吗?

提前感谢您的帮助。

代码如下:

初始化

// generate VBO
glGenBuffers(1, &m_vbo);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferData(GL_ARRAY_BUFFER, m_vertices.size()*sizeof(GLfloat), m_vertices.data(), GL_STATIC_DRAW);

// generate IBO
glGenBuffers(1, &m_ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indices.size()*sizeof(unsigned short), m_indices.data(), GL_STATIC_DRAW);

// generate VAO
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);

// set the vertex attribute pointer
glEnableVertexAttribArray(0);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,vertexSize,reinterpret_cast<const GLvoid*>(0));         

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo);
glBindVertexArray(0);

绘图

glBindVertexArray(m_vao);
glDrawElements(GL_TRIANGLES,size,GL_UNSIGNED_SHORT,reinterpret_cast<const GLvoid*>(0));
glBindVertexArray(0);

另外,这样写是不是更干净:

  1. 生成和绑定 VAO
  2. 生成并绑定 IBO 和 BufferData
  3. 生成并绑定 VBO 和 BufferData
  4. EnableVertexAttribArrays 我需要并设置 VertexAttribPointers
  5. 解除绑定 VAO(绑定到 0)

看起来更干净,但我不知道结果是否相同,特别是在第 4 步和第 5 步之间缺少 IBO 绑定。

【问题讨论】:

    标签: c++ opengl graphics vbo


    【解决方案1】:

    解决您的问题:

    A. 设置了 VertexAttribPointers 后是否需要绑定 IBO?如果有,为什么?

    没有。您可以先绑定元素数组(术语中的 IBO),然后再执行顶点属性,但一般来说,它们是 VAO 中的单独绑定。例如,您可以绑定您的 IBO 以及多个 VBO,并使用 IBO 中的数据使用glDrawElements(和变体)进行渲染,或者使用仅使用 VBO 中的顺序顶点数据的glDrawArrays(和变体)进行渲染- 渲染命令决定是否使用 IBO。

    B. VAO 是否真的同时存储了 VBO 和 IBO?

    是的。一个 VAO 可以存储单个 IBO 和至少 16 个 VBO 的绑定信息。

    我听说它只存储绑定的 last 缓冲区,这意味着我必须像这样渲染:

    绑定VAO
    绑定VBO
    绘制元素
    解除绑定 VAO

    正如您在原始帖子中所推测的那样,此陈述是不正确的,并且您包含的 VBO 的绑定是不必要的。一个 VAO 可以存储与实现相关的最大(至少 16 个)VBO 数量,每个 VBO 都可以绑定到一个顶点属性。

    另外,这样写是不是更干净:

    1. 生成和绑定 VAO
    2. 生成并绑定 IBO 和 BufferData
    3. 生成并绑定 VBO 和 BufferData
    4. EnableVertexAttribArrays 我需要并设置 VertexAttribPointers
    5. 解除绑定 VAO(绑定到 0)

    是的。正如您所指出的,这仅允许您在三个命令中进行绑定、渲染和清理。

    真的,这就是 VAO 的全部意义,收集所有这些绑定和顶点属性关联,这样您就可以一次性完成所有的管道工作,然后一劳永逸。

    【讨论】:

    • 我遇到了一个问题,表明 VAO 没有记住绑定的缓冲区(这就是我发现这个的原因)。我有两种不同的形状,使用不同的 VAO、VBO 和 IBO 集。如果我只在渲染之前绑定 VAO,那么第一个初始化的形状会被第二个形状破坏。绑定 VBO 和 IBO 也解决了这个问题。这让我很困惑,因为我发现的所有文档和教程都表明我不需要这样做。有什么解释吗?
    • VAO 绑定不记得 VBO 绑定(在某种意义上,调用 glBindBuffer(GL_ARRAY_BUFFER, VBO) 不会影响 VAO 的状态;并且更改绑定 VAO 不会影响哪个 VBO 是边界)。然而,当您调用 glVertexAttribPointer 时,VAO 会存储 VBO 的数据所在的位置(因此在使用 VAO 进行绘图时不需要绑定 VBO)。此外,VAO 确实记得 EBO/IBO 绑定。这提供了一个很好的概述:learnopengl.com/Getting-started/Hello-Triangle
    • 另一个很好的描述:gamedev.stackexchange.com/a/99238/35574
    • glEnableVertexAttribArrays 只需要在创建 VAO 时调用一次。如果你把你的draw call包装在这些里面,你就错了。
    猜你喜欢
    • 1970-01-01
    • 2012-07-24
    • 1970-01-01
    • 1970-01-01
    • 2021-11-04
    • 1970-01-01
    • 1970-01-01
    • 2020-07-21
    • 1970-01-01
    相关资源
    最近更新 更多