顶点缓冲区绑定索引和统一缓冲区绑定点?

时间:2020-09-20 16:33:31

标签: opengl

只需了解统一缓冲区及其工作方式即可。在属性和缓冲区绑定方面,它们似乎与顶点缓冲区具有相似之处。
由于我不想将缓冲区绑定点直接硬编码到glBindBufferBaseglUniformBlockBinding中,并且为了将来进行自动着色器合成,我尝试将顶点着色器缓冲区和统一缓冲区合并为一个单独的概念C ++中的缓冲区类。

这是我现在的心理模型:

enter image description here

这两者都是正确的看法吗?
属性位置,顶点缓冲区和绑定索引

统一的位置,统一的缓冲区和绑定点

1 个答案:

答案 0 :(得分:1)

您的类比的基本事实大致正确(假设我们使用的是顶点属性绑定)。 GLSL中的顶点属性具有一个位置,该位置最终映射到缓冲区绑定索引,缓冲区对象绑定到该索引。 GLSL中的统一缓冲区具有块索引,该索引最终与缓冲区绑定索引相关联,缓冲区对象绑定到该缓冲区绑定索引。

但是这些东西在细节上有太多差异,以至于无法试图形成任何形式的结构基础,以便在形式化对象中以相同方式对待这些结构。

考虑顶点属性索引和块索引之间的区别。是的,这些在某些方面是相似的。但是,您与他们互动的方式却大不相同。块索引由GLSL编译器分配。用户在代码中 在着色器中通过layout(location)或在编译着色器之前通过glBindAttribLocation来分配属性索引。

简单地说,您查询块索引;您分配顶点属性位置。

现在,如果您想获取技术知识,则如果您未以其他方式分配这些位置,则GLSL编译器将在编译着色器时为每个属性分配一个唯一的位置。因此,您可以查询位置。

但是,这使我们在与他们互动的方式上有了另一种差异。区块索引没什么意义;它们纯粹是着色器中特定均匀块的数字标识符。块索引仅对特定的着色器有用。

这不是属性位置的情况。属性位置和它们从中提取的缓冲区之间的关联包含在与实际着色器分开的对象内:顶点数组对象。这意味着着色器指定的属性位置还必须与VAO中指定的属性格式匹配,以使所有工作正常进行。

因此,属性位置的范围不仅限于一个着色器。它必须与打算使用的任何VAO一致。或更重要的是,特定VAO的属性位置必须与将使用该VAO的所有着色器匹配。

在许多GPU中,更改顶点格式是一项相当昂贵的操作。因此,保持相同的顶点格式(包括位置与绑定的关联)将是一件好事。这意味着拥有多个都使用相同VAO的着色器是合理的。您将更改绑定的缓冲区以呈现不同的对象(状态更改比格式更快),但是您不会在这些对象之间调用glBindVertexArray

要使其正常工作,这些对象的所有着色器必须为其属性使用相同的位置。但是,即使它们使用相同的统一块定义,它们也不一定具有相同的块索引。

统一块索引值是任意的;位置不是。这就是为什么您可以分配位置但不能分配块索引的原因。

这也是为什么可以在着色器中(通过layout(binding=#)分配UBO binding 索引,但是不能从着色器分配属性绑定索引的原因。着色器无法控制绑定索引。 VAO会这么做。

实际上,在着色器中将绑定索引分配给UBO的能力使从根本上消除块索引成为可能。您可以开发一组具有明确定义含义的已知绑定索引。索引0可以用于每个场景的数据(摄像机,透视矩阵等),索引1可以用于每个对象的数据,索引2可以用于照明,索引3可以用于骨骼矩阵阵列,等等。

但是对属性的类似启发式使用位置,而不是顶点缓冲区绑定索引。位置0可能代表位置,位置1代表法线,位置2代表颜色,等等。

因此,从这个角度来看,从我们用来与之交谈的GLSL代码的角度来看,属性位置可以看作与UBO绑定索引更相似。尽管事实上您没有将缓冲区绑定到属性位置。

还要看看绑定时与缓冲区交互的方式的不同。 UBO缓冲区绑定是显式范围的。您可以使用glBindBufferBase来绑定整个缓冲区,但这不是预期的用法。通常,拥有一堆小缓冲区对象不是一个好主意。而且,如果您使用UBO存储每个对象的数据,则可能只想映射一个缓冲区,一次传输所有对象数据,然后再使用它,而不必一次又一次地绑定不同的缓冲区。

因此,UBO绑定API的正常用法是将一小组缓冲区的适当子范围绑定到特定的绑定点。

相比之下,顶点数组缓冲区绑定是未绑定的。您提供了一个起始偏移量,但是范围没有上限。渲染调用可以从缓冲区存储区中的任何字节中获取(偏移之后)。

这很重要,因为实例化和基本顶点渲染之类的功能可以让您将多个对象存储在同一缓冲区中,而不必绑定新缓冲区来渲染另一个对象。顶点缓冲区绑定虽然不是很昂贵,但它并不是世界上最便宜的东西,如果可以避免的话,应该这样做。

这是另一个区别。 UBO中存储的数据格式最终由着色器本身定义。您的C ++代码必须提供与GLSL着色器代码中的UBO块定义所定义的布局完全匹配的数据。

相比之下,存储在顶点缓冲区中的数据格式很大程度上由 VAO 而不是着色器定义。类型vec4的属性可以从4个浮点数的组中获取其数据,从4个标准化的无符号字节转换为浮点数,从4个非数字化的带符号的short数值转换为浮点数,或其他多种选择。

同样,尽管采用了相似的概念,但与它们的交互却截然不同。因此,尝试构建一个通过代码结构使这两种机制相似的系统将是不合适的。