OpenGL有多少VAO

lyn*_*nks 16 opengl vao

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

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

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

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

我刚读过这个问题; OpenGL VAO最佳实践,告诉我我的方法是错误的,并且我应该使用更多的VAO来保存每次设置整个场景的工作.

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

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

tho*_*kra 14

显然,如果场景中的每个静态表面都有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设置的某个特定速率更改.

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

glVertexAttribPointer(0, 4, ....);
Run Code Online (Sandbox Code Playgroud)

glVertexAttribPointer(1, 3, ....);
Run Code Online (Sandbox Code Playgroud)

可以定义两个索引为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; 
Run Code Online (Sandbox Code Playgroud)

要么

/*layout(location = 1)*/ in vec3 Position;
Run Code Online (Sandbox Code Playgroud)

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

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

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

一般来说:你可以尝试这些东西很多.做吧!

  • VAO存储顶点属性索引和相应的缓冲区绑定之间的映射列表。当调用glVertexAttribPointer时,当前绑定到ARRAY_BUFFER的缓冲区对象的名称被记录为指定索引并存储在VAO中。这就是 VAO 将索引和缓冲区对象关联起来的方式。可以使用glGetVertexAttribiv()和VERTEX_ATTRIB_ARRAY_BUFFER_BINDING查询对应的值。另请参见 GL 3.3 核心规范第 6.2 节(状态表)中的表 6.5。 (2认同)