在GLSL中从数组初始化结构

Initializing structures from arrays in GLSL

本文关键字:初始化 结构 数组 GLSL      更新时间:2023-10-16

假设我在着色器中有一个数组变量,在着色器存储块中声明:

layout(std430, binding = 2) buffer MyBuffer
{
  float lotsOfFloats[];
};

和struct:

struct myStruct
{
 float f1;
 vec3 vf1;
}struct1;

是否有一种方法来"快速"初始化这个结构的对象在着色器中使用的值在一个缓冲区存储块(在lotsOfFloats数组在这个例子)?例如,在c++中可以将内存从数组复制到对象:

memcpy(&struct1, &lotsOfFloats[0], sizeof(myStruct) );

或者可以通过赋值将数组值字节复制到对象中:

struct1 = *(myStruct*)&lotsOfFloats[0];

在GLSL中是否有类似的方法?例如,将工作的第二种方式(字节拷贝赋值)在GLSL?

与其将SSB视为浮点数的非结构化数组,不如将其声明为结构的非大小数组:

struct myStruct
{              // Addresses Occupied
  float f1;    // 0N
  vec3  vf1;   // 1N,2N,3N
};
layout(std430, binding = 2) buffer MyBuffer
{
  myStruct lotsOfStructs[];
};

有一个小问题与你的结构,它目前的方式编写:

gpu不喜欢大多数3-component数据类型,通常必须像对待4-component那样对待它们。因此,vec3具有与vec4相同的对齐规则。

现在,你有一个vec3开始在错误的边界。vec3vec4数据类型需要对齐到4N的倍数(其中N是float的大小)。

以下更改通过重新安排vf1f1来解决此问题:

struct myStruct
{              // Addresses Occupied
  vec3  vf1;   // 0N,1N,2N
  float f1;    // 3N
};

(单精度)标量可以在任何边界上对齐,因为它们的大小为1N,所以你可以把f1放在vf1后面,没有问题。


您可能会发现,在std430中,有一个额外的要求,即结构体的大小必须是最大基数对齐的倍数。在这种情况下,这个结构体中所有成员的最大基数对齐是vf1 (vec3),它的基数对齐是4N。

这意味着如果你在结构的末尾没有f1(它的大小将是3N), GL将自动添加1N值的填充到结构的末尾,你需要在你的C代码中考虑GL的行为。你的结构已经对齐了4N,所以你可以开始了,但如果你不知道这一点,它可能会让你大吃一惊。

你应该仔细阅读 7.6.2.2 Standard Uniform Block Layout ,在处理着色器存储缓冲区和统一缓冲区时,对齐是非常重要的。