显然,我的方法只使用一个VAO是不优化的。在场景中为每个静态表面分配一个VAO是不必要的,因为切换VAO会消耗大量资源。如果你的场景中有几百或几千个对象同时可见,并且每个对象都需要单独的VAO,则需要频繁切换VAO才能渲染这些对象。如果有多个对象共享相同的内存布局(即元素的大小/类型/归一化和步幅都相同),为什么要定义多个存储相同信息的VAO呢?您可以通过对应的绘制调用直接控制从哪里开始提取顶点属性。
对于非索引几何体来说,这很简单,因为您在gl[Multi]DrawArrays*()中提供一个
first参数(或者在多绘制情况下提供偏移量数组),该参数定义了关联ARRAY_BUFFER的数据存储器中的偏移量。
对于索引几何体,如果在单个ELEMENT_ARRAY_BUFFER中存储了多个对象的索引,则可以使用gl[Multi]DrawElementsBaseVertex提供常量偏移量以供索引使用,或者在上传到缓冲对象之前手动添加常量偏移量来偏移索引。
提供偏移量可以将多个不同的对象存储在单个ARRAY_BUFFER中,将相应的索引存储在单个ELEMENT_ARRAY_BUFFER中。但是,缓冲区对象的大小应根据您的硬件而定,因为各个供应商的建议不同。
我为每个顶点编写一个uniform变量,这样做正确吗?我读到过 uniform shader 变量不应在帧中间更改,如果我可以向我的uniform变量写入不同的值,那么uniforms和vertex shader中的普通in变量有什么区别?
首先,声明为
in/out的uniforms和shader输入/输出变量在各种情况下都有所不同:
• 输入/输出变量定义了着色器阶段之间的接口,即一个着色器阶段的输出变量由后续阶段中相应且同名的输入变量支持。如果使用相同名称声明,则uniform在所有阶段都可用,并且在应用程序更改之前保持不变。
• 顶点着色器内部的输入变量来自ARRAY_BUFFER。uniform块中的uniform由UNIFORM_BUFFER支持。
• 输入变量也可以使用glVertexAttrib*()系列函数直接编写。使用glUniform*()系列函数编写单个uniforms。
• uniforms的值是程序状态。输入变量的值不是。
语义上的差异也很明显:uniforms通常在一组基元中保持不变,而输入变量通常由于插值而针对每个顶点或片元而变化。
编辑:为了澄清并考虑到Nicol Bolas的意见:应用程序不能更改单个绘制调用提交的一组顶点的uniforms,也不能通过调用glVertexAttrib*()更改顶点属性。由缓冲区对象支持的顶点着色器输入将每个顶点更改一次或以某种指定的速率更改,该速率由glVertexAttribDivisor设置。
编辑2:为了澄清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
in vec4 Position;
或者
in vec3 Position;
可以直接将数据绑定到索引0或1处,也可以使用glBindAttribLocation()函数来绑定,但仍然使用同一个VAO。据我所知,规范没有说明如果一个属性被启用但当前着色器没有源数据会发生什么,但我猜测在这种情况下实现可能会简单地忽略该属性。
无论您是否从同一缓冲对象中获取上述属性的数据都是另一个问题,但当然是可能的。
个人而言,我倾向于每个布局使用一个VBO和VAO,即如果我的数据由具有相同属性的相等数量的属性组成,则将它们放入单个VBO和单个VAO中。
总体而言:您可以对此进行大量实验。去尝试吧!
glDrawElements
和glUniformMatrix4
来通过更新被声明为uniform mat4 model
的模型矩阵在不同的位置绘制相同的VAO。我只能假设这是有效的,因为我的立方体出现在了预期的位置,而这些位置没有被用于其他任何用途。 - lynks