从GLSL中的数组初始化结构 [英] Initializing structures from arrays in GLSL

查看:2580
本文介绍了从GLSL中的数组初始化结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 布局(std430,binding = 2)buffer MyBuffer 
{
float lotOfFloats [];
};

和结构:

  struct myStruct 
{
float f1;
vec3 vf1
} struct1;

有一种方法可以在着色器中快速初始化此结构的对象,在缓冲存储块中的数组(在这个例子中的lotsOfFloats数组)?说,在C ++中,可以将数组中的内存复制到对象:

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

或者可以通过赋值给对象的字节拷贝数组值:

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

GLSL中有类似的方法吗?例如。将在GLSL中工作第二种方式(字节复制赋值)

解决方案

不是把你的SSB看成一个非结构化的浮点数组,你实际上可以将它声明为一个未定义的结构数组:

  struct myStruct 
{//地址占用
float f1; // 0N $ ​​b $ b vec3 vf1; // 1N,2N,3N
};

layout(std430,binding = 2)buffer MyBuffer
{
myStruct lotsOfStructs [];
};






它目前是写为:



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



现在,你有一个 vec3 从错误的边界开始。 vec3 vec4 数据类型需要对齐到4N的倍数(其中N是<$以下更改通过重新安排 vf1 来解决此问题:c $ c> float $ c>和 f1

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

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






您可能会发现使用 std430 有用的是,有一个额外的要求,结构的大小必须是是最大碱基对齐的倍数。在这种情况下,此结构中任何成员的最大基准对齐为 vf1 vec3 ),



这意味着如果你在结构的末尾没有 f1 将是3N),GL会自动添加1N值填充到结构的结尾,你需要考虑GL的行为在你的C代码。你的结构已经是4N对齐的,所以你很好去,但如果你不知道,以后可能会有一个惊喜。



7.6.2.2标准统一块布局 ,在处理着色器存储缓冲区和统一缓冲区时,对齐非常重要。


Suppose I have an array variable in a shader, declared in a shader storage block:

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

and a struct:

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

Is there a way to "quickly" initialize an object of this structure in a shader using the values in the array in a buffer storage block ( in the lotsOfFloats array in this example)? Say, in C++ one can copy memory from the array to the object:

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

Or one can byte copy array values to the object through assignment:

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

Is there a similar way in GLSL? E.g. will work the second way (byte copy assignment) in GLSL?

解决方案

Rather than treating your SSB as an unstructured array of floats, you can actually declare it as an unsized array of your structure:

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

layout(std430, binding = 2) buffer MyBuffer
{
  myStruct lotsOfStructs[];
};


There is one minor problem with your struct the way it is currently written:

GPUs do not like most 3-component data types and generally have to treat them like 4-component for proper alignment. Thus, vec3 has the same alignment rules as vec4.

Right now, you have a vec3 beginning on the wrong boundary. vec3 and vec4 data types need to be aligned to a multiple of 4N (where N is the size of a float).

The following change addresses this issue by re-arranging vf1 and f1:

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

(Single-precision) scalars can be aligned on any boundary since they have a size 1N, so you can put f1 right after vf1 with no problems.


You might find it useful to know that with std430, there is one additional requirement that says the size of the struct must be a multiple of the largest base alignment. In this case the largest base alignment of any member in this struct is for vf1 (vec3), which has a base alignment of 4N.

That means that if you did not have f1 at the end of the structure (its size would be 3N), GL would automatically add 1N worth of padding to the end of the structure and you would need to account for GL's behavior in your C code. Your structure is already 4N aligned, so you are good to go, but if you did not know this it could come a surprise later on.

You should read up on 7.6.2.2 Standard Uniform Block Layout, alignment is very important when dealing with Shader Storage Buffers and Uniform Buffers.

这篇关于从GLSL中的数组初始化结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆