OpenGL有多少VAO

时间:2013-08-28 10:28:31

标签: opengl vao

我正在编写一个OpenGL3 +应用程序,并对VAO的使用感到困惑。现在我只有一个VAO,一个围绕原点的标准化四边形集。这个单一的VAO包含3个VBO;一个用于位置,一个用于曲面法线,一个用于索引(因此我只能存储4个顶点,而不是6个)。

我已经设置了一些辅助方法来将对象绘制到场景中,例如drawCube()获取位置和旋转值并遵循该过程;

  • 绑定四核VAO。
  • 每立方体脸:
    • 创建一个代表此脸部的模型矩阵。
    • 将模型矩阵上传到uniform mat4 model顶点着色器变量。
    • 调用glDrawElements()将四边形绘制到此面部的位置。

我刚刚开始添加每个立方体颜色的任务,并意识到我不能将我的颜色VBO添加到单个VAO中,因为它会随着每个立方体而改变,这感觉不对。

我刚读过这个问题; OpenGL VAO best practices,它告诉我我的方法是错误的,我应该使用更多的VAO来保存每次设置整个场景的工作。

应该使用多少个VAO?显然,如果场景中的每个静态曲面都有VAO,那么我的1的方法并不是最优的吗?那些移动的是什么?

我正在为每个顶点写一个统一变量,这是正确的吗?我读到uniform着色器变量不应该在帧中间改变,如果我能写出不同的值对于我的uniform变量,制服与顶点着色器中的简单in变量有何不同?

1 个答案:

答案 0 :(得分:13)

  

显然,如果场景中的每个静态曲面都有VAO,那么我的1的方法不是最优的吗?

绝对不是。切换VAO的成本很高。如果在场景中为每个对象分配一个VAO,则需要在渲染此类对象之前切换VAO。扩展到目前可见的几百或几千个对象,您可以获得尽可能多的VAO更改。问题是,如果你有多个共享公共内存布局的对象,即元素的大小/类型/规范化/跨步是相同的,为什么要定义多个存储相同信息的VAO?您可以使用相应的绘制调用直接控制要从中直接拉动顶点属性的偏移量。

对于非索引几何,这是微不足道的,因为你在gl [Multi] DrawArrays *()中提供了第一个(或多绘制情况下的偏移数组)参数,它定义了偏移到关联的ARRAY_BUFFER的数据存储中。

对于索引几何,如果在单个ELEMENT_ARRAY_BUFFER中存储多个对象的索引,则可以使用gl [Multi] DrawElementsBaseVertex为索引提供常量偏移,或者通过在将索引上传到缓冲对象。

能够向缓冲存储区提供偏移量还意味着您可以在单个ARRAY_BUFFER中存储多个不同的对象,并在单个ELEMENT_ARRAY_BUFFER中存储相应的索引。但是,缓冲区对象的大小取决于您的硬件和供应商的建议不同。

  

我正在为每个顶点写一个统一变量,这是正确的吗?我读到统一着色器变量不应该在中间框架中改变,如果我能够为我的均匀变量写入不同的值,那么制服与顶点着色器中的简单变量有何不同?

首先,在各种情况下,声明为 in / out 的制服和着色器输入/输出变量有所不同:

  • 输入/输出变量定义着色器阶段之间的接口,即一个着色器阶段中的输出变量由下一阶段中相应且同名的输入变量支持。如果使用相同的名称声明并且在应用程序更改之前保持不变,则可以在所有阶段使用制服。

  • 顶点着色器内的输入变量从ARRAY_BUFFER填充。统一块内的制服支持UNIFORM_BUFFER。

  • 输入变量也可以使用glVertexAttrib *()系列函数直接编写。单一制服是使用glUniform *()系列函数编写的。

  • 制服的价值是程序状态。输入变量的值不是。

语义差异也应该是显而易见的:正如其名称所示,制服在一组基元中通常是不变的,而输入变量通常会根据顶点或片段而变化(由于插值)。

编辑:澄清并考虑Nicol Bolas的评论:通过单个绘制调用提交的一组顶点的应用程序不能更改制服,也不能通过调用glVertexAttrib *来顶点属性()。由缓冲区对象支持的顶点着色器输入将每个顶点更改一次或由glVertexAttribDivisor设置的某个特定速率更改。

EDIT2 :为了阐明VAO理论上如何存储多个布局,您可以简单地定义多个具有不同索引但语义相同的数组。例如,

glVertexAttribPointer(0, 4, ....);

glVertexAttribPointer(1, 3, ....);

可以定义两个索引为0和1的数组,组件大小为3和4,两者都引用顶点的位置属性。但是,根据您要渲染的内容,您可以绑定假设的顶点着色器输入

// if you have GL_ARB_explicit_attrib_location or GL3.3 available, use explicit
// locations
/*layout(location = 0)*/ in vec4 Position; 

/*layout(location = 1)*/ in vec3 Position;

显式索引0或1或glBindAttribLocation()并仍然使用相同的VAO。 AFAIK,规范没有说明如果某个属性已启用但未被当前着色器采购会发生什么,但我怀疑实现只是忽略该属性。

是否从相同或不同的缓冲区对象中获取所述属性的数据是另一个问题,但当然可能。

就个人而言,我倾向于每个布局使用一个VBO和VAO,即如果我的数据由具有相同属性的相同数量的属性组成,我将它们放入单个VBO和单个VAO中。

一般情况下:你可以尝试这些东西很多。做吧!