【问题标题】:Dynamic-length arrays as Shader Storage Buffer Objects动态长度数组作为着色器存储缓冲区对象
【发布时间】:2020-01-04 18:37:00
【问题描述】:

假设我有一个动态数量的“球”,我想在我的 OpenGL 着色器中访问它们。在 C++ 中,数据可能是这样的:

struct Ball
{
    glm::vec3 position;
    glm:vec3 colour;
    float size;
};

std::vector<Ball> all_balls;

如果我想在片段着色器中迭代all_balls,我相信我需要一个着色器存储缓冲区对象。

This documentation 涉及数组,但明显不完整。

我假设我可以像这样将数据发送到缓冲区

glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, all_balls.size() * sizeof(Ball), &(all_balls[0]), usage);

在 GLSL 中,我如何指定缓冲区是一个数组,我的着色器如何知道这个数组的大小?

【问题讨论】:

标签: opengl glsl shader-storage-buffer buffer-objects


【解决方案1】:

当使用长度不是编译时间常数的数组时,可以将SSBO Interface Block 的成员声明为未确定长度。

假设存在适合 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++ 结构布局可能会导致对齐问题。您可能想阅读Should I ever use a vec3 inside of a uniform buffer or shader storage buffer object?(感谢 Rabbid76 的提示)

【讨论】:

  • 当您使用sizeof(unsigned int) 作为glBufferSubData 中的偏移量时,我认为元素偏移量被四舍五入为sizeof(vec4) 的倍数。对吗?
  • @spraff:不,为什么会这样?即使是 140 布局,填充也只与 vec3、数组和结构内的成员相关。
  • @spraff 我正在使用 vulkan,但我试图实现同样的目标。实际上,我确实必须四舍五入到一个 size(vec4) 才能完成这项工作。 (不知道 vulkan/gl 之间有什么区别,但如果有人读到这个,它可能会有用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-03
相关资源
最近更新 更多