假设我在着色器中有一个数组变量,在着色器存储 block 中声明:
layout(std430, binding = 2) buffer MyBuffer
{
float lotsOfFloats[];
};
和一个结构:
struct myStruct
{
float f1;
vec3 vf1;
}struct1;
有没有一种方法可以使用缓冲区存储 block 中数组中的值(在本例中为 lotsOfFloats 数组)在着色器中“快速”初始化此结构的对象?比如,在 C++ 中,可以将内存从数组复制到对象:
memcpy(&struct1, &lotsOfFloats[0], sizeof(myStruct) );
或者可以通过赋值将数组值字节复制到对象:
struct1 = *(myStruct*)&lotsOfFloats[0];
GLSL中有类似的方法吗?例如。将在 GLSL 中以第二种方式(字节复制赋值)工作吗?
最佳答案
与其将您的 SSB 视为非结构化的 float 组,您实际上可以将其声明为您的结构的未调整大小的数组:
struct myStruct
{ // Addresses Occupied
float f1; // 0N
vec3 vf1; // 1N,2N,3N
};
layout(std430, binding = 2) buffer MyBuffer
{
myStruct lotsOfStructs[];
};
您的结构目前的编写方式存在一个小问题:
GPU 不喜欢大多数 3 分量数据类型,通常必须将它们视为 4 分量数据类型才能正确对齐。因此,vec3
与 vec4
具有相同的对齐规则。
现在,您有一个从错误边界开始的 vec3
。 vec3
和 vec4
数据类型需要对齐到 4N 的倍数(其中 N 是 float
的大小)。
以下更改通过重新安排 vf1
和 f1
解决了此问题:
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
, 在处理 Shader Storage Buffers 和 Uniform Buffers 时对齐非常重要。
关于c++ - 从 GLSL 中的数组初始化结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23433202/