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

Opengl 顶点缓冲区绑定索引和统一缓冲区绑定点?,opengl,Opengl,只是学习统一缓冲区及其工作原理。在属性和缓冲区绑定方面,它们似乎与顶点缓冲区有相似之处。 由于我不想直接将缓冲绑定点编码成或将来自动着色器组合,所以我尝试将顶点着色器缓冲区和统一缓冲区结合成C++中缓冲类的单一概念。 以下是我目前的思维模式: 这两种观点都正确吗: 属性位置、顶点缓冲区和绑定索引 & 统一位置、统一缓冲区和绑定点 ?您的类比的基本事实大体上是准确的(假设我们使用顶点属性绑定)。GLSL中的顶点属性具有最终映射到缓冲区绑定索引的位置,缓冲区对象绑定到该索引。GLSL中的统一缓冲区

只是学习统一缓冲区及其工作原理。在属性和缓冲区绑定方面,它们似乎与顶点缓冲区有相似之处。
由于我不想直接将缓冲绑定点编码成或将来自动着色器组合,所以我尝试将顶点着色器缓冲区和统一缓冲区结合成C++中缓冲类的单一概念。 以下是我目前的思维模式:

这两种观点都正确吗:
属性位置、顶点缓冲区和绑定索引
&
统一位置、统一缓冲区和绑定点

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

但是,这些东西的细节有太多的差异,无法尝试形成任何类型的结构基础,以便在形式化对象中以相同的方式处理这些构造

考虑顶点属性索引和块索引之间的区别。是的,这些在某些方面是相似的。然而,你与他们互动的方式是非常不同的。块索引由GLSL编译器指定。在编译着色器之前,属性索引由用户在代码中通过着色器中的
layout(location)
或通过
glBindAttribLocation
指定

简单地说,您可以查询块索引;可以指定顶点属性位置

现在,如果您想获得技术性,GLSL编译器将在编译着色器时为每个属性指定一个唯一的位置,前提是您没有以其他方式指定这些位置。因此,您可以查询位置

但这给我们带来了另一个区别,那就是你如何与他们互动。块索引没有任何意义;它们纯粹是着色器中特定统一块的数字标识符。块索引仅对特定着色器有用

属性位置的情况并非如此。属性位置和它们从中提取的缓冲区之间的关联包含在与实际着色器分离的对象中:顶点数组对象。这意味着着色器指定的属性位置也必须与VAO中指定的属性格式相匹配,才能使一切正常工作

因此,属性位置的范围不仅仅绑定到一个着色器。它必须同意它打算与之一起使用的任何VAO。或者更重要的是,特定VAO的属性位置必须与此VAO将使用的任何着色器匹配

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

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

均匀块索引值是任意的;地点不是。这就是为什么可以指定位置,但不能指定块索引

这也是为什么可以在着色器中指定UBO绑定索引(通过
layout(binding=#)
),但不能从着色器中指定属性绑定索引。着色器不控制绑定索引;VAO是这样的

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

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

因此,从这个角度来看,属性位置可以被看作与我们用来与它们对话的GLSL代码的角度来看的UBO绑定索引更为相似。尽管您没有将缓冲区绑定到属性位置,但仍然可以这样做

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

所以UBO绑定API的正常用法是将一小部分缓冲区的适当子范围绑定到一个特定的绑定点

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

这一点很重要,因为实例化和基本顶点渲染等功能允许您将多个对象存储在同一缓冲区中,而无需绑定新缓冲区来渲染不同的对象。顶点缓冲区绑定虽然不是非常昂贵,但也不是世界上最便宜的东西,如果可以合理地避免它,您应该这样做

这是