6

I was looking for ways to associate attributes with arbitrary groupings of verticies, at first instancing appeared to be the only way for me to accomplish this, but then I stumbled up this question and this answer states :

However what is possible with newer versions of OpenGL is setting the rate at which a certain vertex attribute's buffer offset advances. Effectively this means that the data for a given vertex array gets duplicated to n vertices before the buffer offset for a attribute advances. The function to set this divisor is glVertexBindingDivisor.

(emphasis mine)

Which to me seems as if the answer is claiming I can divide on the number of vertices instead of the number of instances. However, when I look at glVertexBindingDivisor's documentation and compare it to glVertexAttribDivisor's they both appear to refer to the division taking place over instances and not vertices. For example in glVertexBindingDivisor's documentation it states:

glVertexBindingDivisor and glVertexArrayBindingDivisor modify the rate at which generic vertex attributes advance when rendering multiple instances of primitives in a single draw command. If divisor is zero, the attributes using the buffer bound to bindingindex advance once per vertex. If divisor is non-zero, the attributes advance once per divisor instances of the set(s) of vertices being rendered. An attribute is referred to as instanced if the corresponding divisor value is non-zero.

(emphasis mine)

So what is the actual difference between these two functions?

4

2 回答 2

7

好的,首先是一些背景故事。

从 OpenGL 4.3/ARB_vertex_attrib_binding(AKA:glVertexBindingDivisor从哪里来,所以这是相关的),VAO 在概念上分为两部分:描述单个属性数据价值的顶点格式数组,以及描述数据的缓冲区绑定点数组如何获取数据数组(缓冲区对象、偏移量、步幅和除数)。顶点格式指定其数据来自哪个缓冲区绑定点,以便多个属性可以从同一个数组中获取数据(即:交错)。

当 VAO 被分成这两部分时,旧的 API 会根据新系统重新定义。因此,如果您glVertexAttribPointer使用属性索引调用,此函数将为给定的格式设置顶点格式数据,index并将设置缓冲区绑定状态(缓冲区对象、字节偏移量等)为相同的index。现在,这是两个独立的 VAO 状态数据数组(顶点格式和缓冲区绑定);这个函数只是在两个数组中使用相同的索引。

但是由于顶点格式和缓冲区绑定现在是分开的,glVertexAttribPointer所以也相当于说 index 处的顶点格式从 indexindex处的缓冲区绑定中获取数据index。这很重要,因为这不是自动的。vertex_attrib_binding 的全部意义在于一个索引处的顶点格式可以使用来自不同索引的缓冲区绑定。因此,当您使用旧 API 时,它会通过将 format 链接index到 binding将自身重置为旧行为index

现在,所有这些与除数有什么关系?好吧,因为我刚才说的那件事实际上是他们之间的唯一区别。

glVertexAttribDivisor是用于设置除数的旧式 API。它需要一个属性索引,但它作用于作为缓冲区绑定点一部分的状态(实例化是每个数组的构造,而不是现在的每个属性构造)。这意味着该函数假定(在新系统中)属性 atindex从缓冲区绑定点 at 获取其数据index

而且我刚才说的有点假。它通过直接设置顶点格式以使用该缓冲区绑定点来强制执行此“假设” 。也就是说,它执行与之前相同的最后一步。glVertexAttribPointer

glVertexBindingDivisor是现代功能。它没有传递属性索引;它传递了一个缓冲区绑定索引。因此,它不会更改属性的缓冲区绑定索引。

所以glVertexAttribDivisor完全等价于:

void glVertexAttribDivisor(GLuint index, GLuint divisor)
{
  glVertexBindingDivisor(index, divisor);
  glVertexAttribBinding(index, index);
}

显然,glVertexBindingDivisor不做最后一部分。

于 2018-06-01T22:34:24.733 回答
2

那么这两个功能之间的实际区别是什么?

现代 OpenGL 有两种不同的 API 用于指定顶点属性数组及其属性。传统glVertexAttribArray和朋友,哪里glVertexAttribDivisor也是一部分。

随着ARB_vertex_attrib_binding(自 GL 4.3 以来的核心),引入了一个新的 API,它将顶点格式与指针分开。预计切换数据指针会很快,而切换顶点格式可能会更昂贵。新的 API 允许明确地分别控制这两个方面,而旧的 API 总是同时设置这两个方面。

对于新的 API,引入了一个新的层:缓冲区绑定点。(有关更多详细信息,请参阅OpenGL wiki。)glVertexBindingDivisor为此类绑定点指定属性实例化除数,因此它在概念上等同glVertexAttribDivisor于新 API 的函数。

于 2018-06-01T20:48:09.650 回答