【问题标题】:Is it necessary to bind all VBOs (and textures) each frame?是否有必要每帧绑定所有 VBO(和纹理)?
【发布时间】:2017-03-19 05:26:57
【问题描述】:

我正在关注basic tutorial on OpenGL 3.0。我不清楚为什么/如果我必须绑定、启用和取消绑定/禁用每帧的所有顶点缓冲区和纹理。

对我来说,似乎有太多 gl**** 调用,我想这有一些开销。例如here 你会看到每一帧都有几个块,比如:

// do this for each mesh in scene
// vertexes
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glVertexAttribPointer(  0, 3, GL_FLOAT,GL_FALSE,0,(void*)0);
// normals
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, normal_buffer );
glVertexAttribPointer(  1, 3, GL_FLOAT,GL_FALSE,0,(void*)0);
// UVs
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, uv_buffer    );
glVertexAttribPointer(  2, 2, GL_FLOAT,GL_FALSE,0,(void*)0);

// ...
glDrawArrays(GL_TRIANGLES, 0, nVerts );
// ...
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);

想象一下,您不仅有一个,而是 100 个不同的网格,每个网格都有自己的 VBO,用于顶点、法线、UV。我真的应该为他们每个人的每一帧都做这个程序吗?当然我可以将这种复杂性封装到一些函数/对象中,但我担心这个 gl**** 函数调用的开销。

这台机器的某些部分不可能从per frame loop 移动到scene setup 吗?

另外I read VAO 是一种如何将一个对象的相应 VBO 打包在一起的方法。并且绑定 VAO 会自动绑定相应的 VBO。所以我在想每个网格(不是实例)可能有一个 VAO 应该如何完成 - 但根据 this answer 似乎不是这样?

【问题讨论】:

  • 优化该代码的第一步是一组缓冲区 + 每个“对象”一个 VAO。 第二 优化该代码的步骤是一组缓冲区 + 每个“共享相同顶点属性格式的对象组”一个 VAO(通过拥有更大的缓冲区,在其中组合多个对象)。跨度>
  • 如果您只有 100 个对象,那么切换每个对象的 VAO 甚至应该不会接近性能瓶颈。

标签: c++ opengl vbo vao


【解决方案1】:

您应该使用顶点数组对象(由glGenVertexArrays 生成)。多亏了它,您不必每次都执行这些调用。顶点缓冲区对象存储:

  • 致电glEnableVertexAttribArrayglDisableVertexAttribArray
  • 顶点属性配置通过glVertexAttribPointer
  • 通过调用与顶点属性关联的顶点缓冲区对象 glVertexAttribPointer

也许this 会是更好的教程。

这样您就可以生成 vao 对象,然后绑定它,执行调用并取消绑定。现在在绘图循环中你只需要绑定 vao。

示例:

  glUseProgram(shaderId);
  glBindVertexArray(vaoId);
  glDrawArrays(GL_TRIANGLES, 0, 3);
  glBindVertexArray(0);
  glUseProgram(0);

【讨论】:

    【解决方案2】:

    首先要做的事:您对 GL 调用开销的担忧已通过引入 顶点数组对象 得到解决(请参阅 @Criss 答案)。但是,您思路的真正问题是,您将 VBO 等同于几何网格,即为每个几何图形赋予其自己的 VBO。

    这不是您应该如何看待和使用 VBO。 VBO 是内存块,您可以将多个对象的数据放入单个 VBO;您不必绘制整个事物,您可以将绘制调用限制为 VBO 的子集。 并且您可以使用相似甚至相同的绘图设置合并几何图形,并通过一次绘图调用一次绘制它们。要么拥有正确的顶点索引列表,要么使用实例化。

    当涉及到纹理的绑定状态时……嗯,是的,这有点烦人。切换纹理时,您确实必须完成整个绑定舞蹈。这就是为什么通常在绘制之前按纹理/着色器对几何图形进行排序的原因,这样可以最大限度地减少纹理切换的数量。

    最后 3 或 4 代 GPU(截至 2016 年底)确实支持无绑定纹理,您可以通过 64 位句柄访问纹理(实际上是 some中相关数据结构的地址> 地址空间)在着色器中。然而,无绑定纹理尚未成为核心 OpenGL 标准,您必须使用供应商扩展来使用它。

    另一个有趣的方法(由 Id Tech 4 推广)是虚拟纹理。您可以分配可寻址大小巨大的稀疏填充纹理对象,但实际上只有其中一部分填充了数据。在程序执行期间,您确定需要纹理的哪些区域并根据需要交换所需的数据。

    【讨论】:

      猜你喜欢
      • 2012-04-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-22
      • 1970-01-01
      相关资源
      最近更新 更多