我问自己一个关于UBO的问题,以及使用统一块在GLSL中访问它们的方式。
根据官方文档,如果我想设计一个灯光阵列,我可能会写:
layout(std140, binding = 0) uniform LightBlock
{
vec4 position;
vec4 direction;
vec4 color;
...
} lights[8];
现在我看到很多例子,其中统一代码块是这样写的:
struct LightStruct
{
vec4 position;
vec4 direction;
vec4 color;
...
};
layout(std140, binding = 0) uniform LightBlock
{
LightStruct lights[8];
};
这两种方式有什么区别?
我想这可能有助于减少着色器中使用的统一变量的数量,但我不确定。
第一个
layout(std140, binding = 0) uniform LightBlock { vec4 position; vec4 direction; vec4 color; ... } lights[8];
声明UBO缓冲区块本身的数组。这意味着,您可以为数组中的每个索引绑定不同的缓冲区对象,或者为不同的缓冲区范围绑定。请注意,在此示例中,您将使用从0到7的UBO绑定索引,GLSL spec明确声明:
如果绑定标识符与统一存储或着色器存储一起使用,实例化为数组的块,数组的第一个元素采用指定的块绑定,并且每个后续元素采用下一个连续的统一块绑定点。
这有两个含义:-您只能使用非常有限的数组大小,因为UBO绑定点的数量是有限的-您必须仅使用动态统一表达式为这些数组建立索引-您可以将相同的UBO和缓冲区范围绑定到数组的某些或全部个体索引(某些操作无法在块内使用数组)
总之,您实际上很少真正想要使用统一块的数组。特别是对于您的简单示例,您将使用后者:
layout(std140, binding = 0) uniform LightBlock { LightStruct lights[8]; };
仅声明一个统一块,其中包含aeeay。这意味着您必须为该数组提供一个连续的UBO缓冲区范围,因此您只消耗了宝贵的UBO绑定点之一,并且您可以使数组与实现的最大UBO大小一样大。