2

我必须做哪些布局和绑定才能使(工作的)着色器存储缓冲区在第二个着色器程序中可读?我设置并填充了一个成功绑定并在几何着色器中使用的 SSBO。该着色器读取和写入该 SSBO - 到目前为止没有问题。那里没有进行渲染。
在下一步中,我的渲染通道(第二个着色器程序)应该可以访问这些数据。这个想法是拥有一个大数据集,而第二个程序的顶点着色器只使用每个渲染调用的一些索引来选择该 SSBO 的某些值。

我错过了一些特定的绑定命令还是我把它们放在了错误的位置?
两个程序的布局是否一致?我搞砸了实例吗?
我只是找不到在两个程序中使用的 SSBO 的任何示例..

创建、填充和绑定:

float data[48000];
data[0] = -1.0;
data[1] = 1.0;

data[2] = -1.0;
data[3] = -1.0;

data[4] = 1.0;
data[5] = -1.0;

data[6] = 1.0;
data[7] = 1.0;

data[16000] = 0.0;
data[16001] = 1.0;

data[16002] = 0.0;
data[16003] = 0.0;

data[16004] = 1.0;
data[16005] = 0.0;

data[16006] = 1.0;
data[16007] = 1.0;


GLuint ssbo;
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_DYNAMIC_COPY);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssbo);  

在几何着色器中实例化

layout(std140, binding = 1) buffer mesh
{
    vec2 points[8000];
    vec2 texs[8000];
    vec4 colors_and_errors[8000];
} mesh_data;  

另一个程序的顶点着色器中的第二个实例

layout(std140, binding = 1) buffer mesh
{
    vec2 points[8000];
    vec2 texs[8000];
    vec4 colors_and_errors[8000];
} mesh_data;  

实例是否相互对抗?现在我没有在渲染循环中发布我的绑定,因为我不确定我在那里做什么。我尝试在更改使用的程序之前/之后进行绑定;没有成功。
有人有想法吗?

编辑:我是否还必须将 SSBO 绑定到渲染循环之外的第二个程序?以不同于第一次绑定的方式?

编辑:虽然我没有解决这个特定的问题,但我发现了一种在 opengl 的意义上可能更多的解决方法。
我在第二个程序中使用了第一个程序的 SSBO 作为顶点属性。这和opengl的索引渲染功能解决了这个问题。

(这应该标记为已解决吗?)

4

1 回答 1

3

看起来您已经完成了大部分工作,但是您应该注意一些事项。

两个程序的布局是否一致?布局(std140,绑定 = 1)缓冲网格

您需要小心这种布局。std140 将四舍五入对齐到 vec4,因此将不再与您从 C 代码提供的数据对齐。在这种情况下,std430 应该适合你。

我是否还必须将 SSBO 绑定到渲染循环之外的第二个程序?以不同于第一次绑定的方式?

一旦绑定了 SSBO,假设两个程序都使用相同的绑定点(在您的示例中,它们是),那么您应该没问题。在程序之间共享数据很好,但需要同步。您可以使用内存屏障强制执行此操作。

您没有提到 VAO,但您只能在绑定 VAO(不是默认的 VAO)后才能使用 SSBO。

我认为这可能最好用一个例子来解释。

第一个程序的顶点着色器。它使用缓冲区数据作为其位置和纹理坐标,然后翻转 Y 中的位置。

layout(std430, binding = 1) buffer mesh {
    vec4 points[3];
    vec2 texs[3];
} mesh_data;
out highp vec2 coords;
void main() {
    coords = mesh_data.texs[gl_VertexID];
    gl_Position = mesh_data.points[gl_VertexID];
    mesh_data.points[gl_VertexID] = vec4(gl_Position.x, -gl_Position.y, gl_Position.zw);
}

第二个程序的垂直着色器。它只使用数据但不修改它。

layout(std430, binding = 1) buffer mesh {
    vec4 points[3];
    vec2 texs[3];
} mesh_data;
out highp vec2 coords;
void main() {
    coords = mesh_data.texs[gl_VertexID];
    gl_Position = mesh_data.points[gl_VertexID];
}

在应用程序中,您需要绑定一个 VAO。

glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

然后设置您的 SSBO。

float const data[] = {
    -0.5f, -0.5f, 0.0f, 1.0,
    0.0f,  0.5f,  0.0f, 1.0,
    0.5f,  -0.5f, 0.0f, 1.0,

    0.0f, 0.0f,
    0.5f, 1.0f,
    1.0f, 0.0f
};
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GL_DYNAMIC_COPY);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssbo);

使用第一个程序进行绘图调用。

glUseProgram(first_program);
glDrawArrays(GL_TRIANGLES, 0, 3);

插入一个内存屏障,以确保在下一个绘图调用尝试从缓冲区读取之前,前一个绘图调用的写入完成。

glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);

使用第二个程序进行绘图调用。

glUseProgram(second_program);
glDrawArrays(GL_TRIANGLES, 0, 3);

我希望能澄清事情!如果您还有其他问题,请告诉我。

于 2019-03-22T22:11:59.103 回答