OpenGL 顶点缓冲区绑定点可以跨不同的 VAO 重用吗?
Can OpenGL vertex buffer binding points be reused across different VAOs?
假设我设置了两个 VAO,使用新的(自 OpenGL 4.3 起)glBindVertexBuffer 机制:
glGenVertexArrays(1, &vaoIndex0);
glGenVertexArrays(1, &vaoIndex1);
...
glBindVertexArray(vaoIndex0)
glBindVertexBuffer(bindingIndex0, ...)
glEnableVertexAttribArray(0)
glVertexAttribFormat(0, ...)
glVertexAttribBinding(0, bindingIndex0)
...
glBindVertexArray(0)
...
glBindVertexArray(vaoIndex1)
glBindVertexBuffer(bindingIndex1, ...)
glEnableVertexAttribArray(0)
glVertexAttribFormat(0, ...)
glVertexAttribBinding(0, bindingIndex1)
...
glBindVertexArray(0)
并假设两者是独立的,除非它们存在于相同的 OpenGL 上下文中;它们绑定不同的缓冲区,将用于绘制不同的东西。
bindingIndex0 是否需要与 bindingIndex1 不同?两个指数相等(或不等)有什么意义吗?
...
编辑:
收到答复后,我开始明白,对于真正知道 "vertex buffer binding point" 是什么,尤其是其范围的人来说,我的问题似乎问的问题与我的本意不同。也许更好的措辞是 "Does one need to go out of one's way to prevent OpenGL vertex buffer binding point indices from being reused, even across multiple VAOs, in order to prevent conflicts?" 但无论如何,现在似乎已经回答了两个问题:不,你不能重用 "binding points",不,你不需要避免索引冲突那样。
所有这些调用都会修改 VAO 状态。所以不,您不能在 VAO 中重复使用这些设置。您当然可以在多个 VAO 中将它们设置为相同,但您必须在设置每个 VAO 时进行一次必要的状态设置调用。
您在代码片段中使用的 bindingIndex0
和 bindingIndex1
值没有任何特殊含义。它们只是在您使用 glBindVertexBuffer()
绑定到绑定索引的缓冲区与您指定为使用该绑定索引的属性之间建立连接。
唯一的条件是绑定索引必须小于您可以查询的值 MAX_VERTEX_ATTRIB_BINDINGS
,保证至少为 16。由于这些调用修改了每个 VAO 状态,您绝对可以对多个 VAO 使用相同的绑定索引。
查看这些较新的状态设置调用的一种方法是它们引入了以前不可用的间接级别:
- 如果没有这些调用,您可以在顶点属性和缓冲区之间建立直接连接,方法是在绑定所需缓冲区时调用
glVertexAttribPointer()
。
- 通过这些较新的调用,顶点属性现在可以连接到绑定索引,该索引是使用
glVertexAttribBinding()
建立的。然后将绑定索引连接到缓冲区,该缓冲区由 glBindVertexBuffer()
. 建立
换句话说,旧式的连接是:
attribute index --> buffer
这些 4.3+ 调用的新样式:
attribute index --> buffer index --> buffer
这种新的灵活性的一个优点是您可以通过一次调用将新缓冲区绑定到多个属性。只要所有这些属性都具有相同的缓冲区索引,您只需调用一次 glBindVertexBuffer()
即可为所有属性指定一个新缓冲区。
半正式定义
以下根本不是官方符号。我刚编的。但我认为通过写下一些伪数据结构来更正式地定义关系可能会有用。
假设每个 VAO 包含两个数组来捕获上述连接:
struct VAO {
...
uint bufferIndexBindings[MAX_VERTEX_ATTRIB_BINDINGS];
uint attribBufferIndices[MAX_VERTEX_ATTRIBS];
}
这里讨论的两个调用会像这样修改这个结构:
glBindVertexBuffer(uint bindingIndex, uint buffer, ...) {
CurrentVAO.bufferIndexBindings[bindingIndex] = buffer;
}
glVertexAttribBinding(uint attribIndex, uint bindingIndex) {
CurrentVAO.attribBufferIndices[attribIndex] = bindingIndex;
}
然后使用此状态获取索引为 attribIndex
的给定属性的缓冲区:
CurrentVAO.bufferIndexBindings[CurrentVAO.attribBufferIndices[attribIndex]]
这也说明了我上面解释的间接寻址,它在这里显示为对状态表的两个级别的查找。
假设我设置了两个 VAO,使用新的(自 OpenGL 4.3 起)glBindVertexBuffer 机制:
glGenVertexArrays(1, &vaoIndex0);
glGenVertexArrays(1, &vaoIndex1);
...
glBindVertexArray(vaoIndex0)
glBindVertexBuffer(bindingIndex0, ...)
glEnableVertexAttribArray(0)
glVertexAttribFormat(0, ...)
glVertexAttribBinding(0, bindingIndex0)
...
glBindVertexArray(0)
...
glBindVertexArray(vaoIndex1)
glBindVertexBuffer(bindingIndex1, ...)
glEnableVertexAttribArray(0)
glVertexAttribFormat(0, ...)
glVertexAttribBinding(0, bindingIndex1)
...
glBindVertexArray(0)
并假设两者是独立的,除非它们存在于相同的 OpenGL 上下文中;它们绑定不同的缓冲区,将用于绘制不同的东西。
bindingIndex0 是否需要与 bindingIndex1 不同?两个指数相等(或不等)有什么意义吗?
...
编辑:
收到答复后,我开始明白,对于真正知道 "vertex buffer binding point" 是什么,尤其是其范围的人来说,我的问题似乎问的问题与我的本意不同。也许更好的措辞是 "Does one need to go out of one's way to prevent OpenGL vertex buffer binding point indices from being reused, even across multiple VAOs, in order to prevent conflicts?" 但无论如何,现在似乎已经回答了两个问题:不,你不能重用 "binding points",不,你不需要避免索引冲突那样。
所有这些调用都会修改 VAO 状态。所以不,您不能在 VAO 中重复使用这些设置。您当然可以在多个 VAO 中将它们设置为相同,但您必须在设置每个 VAO 时进行一次必要的状态设置调用。
您在代码片段中使用的 bindingIndex0
和 bindingIndex1
值没有任何特殊含义。它们只是在您使用 glBindVertexBuffer()
绑定到绑定索引的缓冲区与您指定为使用该绑定索引的属性之间建立连接。
唯一的条件是绑定索引必须小于您可以查询的值 MAX_VERTEX_ATTRIB_BINDINGS
,保证至少为 16。由于这些调用修改了每个 VAO 状态,您绝对可以对多个 VAO 使用相同的绑定索引。
查看这些较新的状态设置调用的一种方法是它们引入了以前不可用的间接级别:
- 如果没有这些调用,您可以在顶点属性和缓冲区之间建立直接连接,方法是在绑定所需缓冲区时调用
glVertexAttribPointer()
。 - 通过这些较新的调用,顶点属性现在可以连接到绑定索引,该索引是使用
glVertexAttribBinding()
建立的。然后将绑定索引连接到缓冲区,该缓冲区由glBindVertexBuffer()
. 建立
换句话说,旧式的连接是:
attribute index --> buffer
这些 4.3+ 调用的新样式:
attribute index --> buffer index --> buffer
这种新的灵活性的一个优点是您可以通过一次调用将新缓冲区绑定到多个属性。只要所有这些属性都具有相同的缓冲区索引,您只需调用一次 glBindVertexBuffer()
即可为所有属性指定一个新缓冲区。
半正式定义
以下根本不是官方符号。我刚编的。但我认为通过写下一些伪数据结构来更正式地定义关系可能会有用。
假设每个 VAO 包含两个数组来捕获上述连接:
struct VAO {
...
uint bufferIndexBindings[MAX_VERTEX_ATTRIB_BINDINGS];
uint attribBufferIndices[MAX_VERTEX_ATTRIBS];
}
这里讨论的两个调用会像这样修改这个结构:
glBindVertexBuffer(uint bindingIndex, uint buffer, ...) {
CurrentVAO.bufferIndexBindings[bindingIndex] = buffer;
}
glVertexAttribBinding(uint attribIndex, uint bindingIndex) {
CurrentVAO.attribBufferIndices[attribIndex] = bindingIndex;
}
然后使用此状态获取索引为 attribIndex
的给定属性的缓冲区:
CurrentVAO.bufferIndexBindings[CurrentVAO.attribBufferIndices[attribIndex]]
这也说明了我上面解释的间接寻址,它在这里显示为对状态表的两个级别的查找。