OpenGL 统一块语法

Séb*_*ans 3 opengl shader glsl

我问自己一个关于 UBO 的问题以及在 GLSL 中使用统一块访问它们的方式。

按照官方文档,如果我想设计一组灯,我可能会写:

layout(std140, binding = 0) uniform LightBlock
{
    vec4 position;
    vec4 direction;
    vec4 color;
    ...
} lights[8];
Run Code Online (Sandbox Code Playgroud)

现在我看到很多例子,其中统一块是这样写的:

struct LightStruct
{
    vec4 position;
    vec4 direction;
    vec4 color;
    ...
};

layout(std140, binding = 0) uniform LightBlock
{
    LightStruct lights[8];
};
Run Code Online (Sandbox Code Playgroud)

这两种方式有什么区别?

我想这可能有助于减少着色器中使用的统一变量的数量,但我不确定。

der*_*ass 5

首先

layout(std140, binding = 0) uniform LightBlock
{
    vec4 position;
    vec4 direction;
    vec4 color;
    ...
} lights[8];
Run Code Online (Sandbox Code Playgroud)

声明一个 UBO 缓冲区块数组本身。这意味着,您可以为数组中的每个索引或不同的缓冲区范围绑定不同的缓冲区对象。请注意,在此示例中,您将使用从 0 到 7 的 UBO 绑定索引,GLSL 规范明确指出:

如果绑定标识符与实例化为数组的统一或着色器存储块一起使用,则数组的第一个元素采用指定的块绑定,每个后续元素采用下一个连续的统一块绑定点。

这有几个含义:

  • 您只能使用非常有限的数组大小,因为 UBO 绑定点的数量是有限的
  • 您必须仅使用动态统一表达式索引这些数组
  • 您可以将相同的 UBO 和缓冲区范围绑定到数组的部分或全部单个索引(您无法使用块内的数组执行此操作)

总之,您很少真的想要使用统一块的数组。特别是对于您的轻型示例,您将使用后者:

layout(std140, binding = 0) uniform LightBlock
{
    LightStruct lights[8]; 
};
Run Code Online (Sandbox Code Playgroud)

只声明一个带有数组的统一块。这意味着您必须为数组提供一个连续的 UBO 缓冲区范围,因此您只使用一个宝贵的 UBO 绑定点,并且您可以拥有与实现的最大 UBO 大小一样大的数组。