当使用长度不是编译时间常数的数组时,可以将SSBO 接口块的成员声明为长度未定。
假设存在适合 C++ 球结构的 GLSL 结构,代码可能看起来像这样:
struct GLSLBall {...};
layout(std430, binding = 0) buffer BallBuffer
{
GLSLBall ball_data[];
}
您可以对所有元素进行迭代,如下所示:
for (int i = 0; i < ball_data.length(); ++i)
{
GLSLBall currentBall = ball_data[i];
}
当元素数量经常变化时,我建议不要每次都重新调整大小/重新分配 SSBO,而是预留足够大的缓冲区一次并将实际使用的元素数量传递给着色器。这可以是一个独立的统一变量 ( uniform uint ballCount;
),也可以像这样将其打包到 SSBO 本身中:
struct GLSLBall {...};
layout(std430, binding = 0) buffer BallBuffer
{
uint ball_length;
GLSLBall ball_data[];
}
然后你只能分配一次内存:
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, ENOUGH_MEMORY_FOR_ALL_CASES, null, usage);
并在每次内容更改时上传数据,如下所示:
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(unsigned int), (unsigned int)all_balls.size());
glBufferSubData(GL_SHADER_STORAGE_BUFFER, sizeof(unsigned int), all_balls.size() * sizeof(Ball), &(all_balls[0]));
然后 glsl 循环类似于
for (int i = 0; i < BallBuffer.length; ++i)
{
GLSLBall currentBall = ball_data[i];
...
}
请注意,由于使用 vec3,您当前的 C++ 结构布局可能会导致对齐问题。您可能想阅读我是否应该使用vec3
统一缓冲区或着色器存储缓冲区对象的内部?(感谢 Rabbid76 的提示)