我一直在寻找将属性与任意顶点分组相关联的方法,起初实例化似乎是我完成此操作的唯一方法,但后来我偶然发现了这个问题,这个答案指出:
但是,较新版本的 OpenGL 可能设置某个顶点属性的缓冲区偏移量前进的速率。实际上,这意味着在属性的缓冲区偏移量前进之前,给定顶点数组的数据将复制到 n 个顶点。设置此除数的函数是glVertexBindingDivisor。
(强调我的)
在我看来,答案似乎是声称我可以除以顶点数而不是实例数。 然而,当我查看glVertexBindingDivisor
的文档并将其与glVertexAttribDivisor
的进行比较时,它们似乎都是指发生在实例而不是顶点上的划分。例如,在glVertexBindingDivisor
的文档中,它指出:
glVertexBindingDivisor 和 glVertexArrayBindingDivisor 修改在单个绘制命令中呈现基元的多个实例时,通用顶点属性的前进速率。如果除数为零,则使用绑定到 bindingindex 的缓冲区的属性每个顶点前进一次。如果除数不为零,则属性将按要渲染的顶点集的每个除数实例前进一次。如果相应的除数值不为零,则属性称为实例化。
(强调我的)
那么这两个功能之间的实际区别是什么?
好的,先说一点背景故事。
从OpenGL 4.3/ARB_vertex_attrib_binding(AKA:glVertexBindingDivisor
来自哪里,所以这是相关的)开始,VAO在概念上分为两部分:描述单个属性数据价值的顶点格式数组,以及描述如何获取数据数组的缓冲区绑定点数组(缓冲区对象, 偏移量、步幅和除数)。顶点格式指定其数据来自哪个缓冲区绑定点,以便多个属性可以从同一数组获取数据(即:交错)。
当VAO被拆分为这两个部分时,旧的API根据新系统重新定义。因此,如果使用属性索引调用glVertexAttribPointer
,此函数将为给定index
的格式设置顶点格式数据,并且它将为同一index
设置缓冲区绑定状态(缓冲区对象、字节偏移量等)。现在,这是两个独立的 VAO 状态数据数组(顶点格式和缓冲区绑定);此函数只是在两个数组中使用相同的索引。
但是由于顶点格式和缓冲区绑定现在是分开的,glVertexAttribPointer
也相当于说索引index
处的顶点格式从索引index
处的缓冲区绑定获取其数据。这很重要,因为这不是自动的;vertex_attrib_binding的全部要点是,一个索引处的顶点格式可以使用来自不同索引的缓冲区绑定。因此,当您使用旧 API 时,它会通过将格式index
链接到绑定index
来将自身重置为旧行为。
现在,这一切与除数有什么关系?好吧,因为我刚才说的那件事实际上是它们之间的唯一区别。
glVertexAttribDivisor
是用于设置除数的旧式 API。它采用属性索引,但它作用于作为缓冲区绑定点一部分的状态(实例化是每个数组的构造,而不是现在的每属性构造)。这意味着该函数假定(在新系统中)index
的属性从index
处的缓冲区绑定点获取其数据。
我刚才说的有点谎言。它通过直接设置顶点格式以使用该缓冲区绑定点来强制执行此"假设"。也就是说,它执行与glVertexAttribPointer
相同的最后一步。
glVertexBindingDivisor
是现代功能。它没有传递属性索引;它传递缓冲区绑定索引。因此,它不会更改属性的缓冲区绑定索引。
所以glVertexAttribDivisor
完全等同于这个:
void glVertexAttribDivisor(GLuint index, GLuint divisor)
{
glVertexBindingDivisor(index, divisor);
glVertexAttribBinding(index, index);
}
显然,glVertexBindingDivisor
没有做最后一部分。
那么这两个函数之间的实际区别是什么?
现代 OpenGL 有两个不同的API 用于指定顶点属性数组及其属性。传统的glVertexAttribArray
和朋友,glVertexAttribDivisor
也是其中的一部分。
随着ARB_vertex_attrib_binding
(从GL 4.3开始的核心),引入了一个新的API,它将顶点格式与指针分开。预计切换数据指针的速度很快,而切换顶点格式的成本可能更高。新 API 允许分别明确控制这两个方面,而旧 API 总是同时设置这两个方面。
对于新的 API,引入了一个新的引入层:缓冲区绑定点。(有关更多详细信息,请参阅 OpenGL wiki。glVertexBindingDivisor
指定此类绑定点的属性实例化除数,因此它在概念上等效于新 API 的glVertexAttribDivisor
函数。