在不同的着色器程序中创建着色器存储缓冲区

问题描述 投票:0回答:1

我需要做什么布局和绑定才能在第二个着色器程序中使(工作)着色器存储缓冲区可读?我设置并填充了一个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的索引渲染功能解决了这个问题。

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

opengl glsl shader shader-storage-buffer
1个回答
0
投票

看起来你大部分都在那里,但有一些事情你应该注意。

这两个程序的布局是否一致? layout(std140,binding = 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);
}

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

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);

我希望澄清事情!如果您有任何其他问题,请与我们联系。

© www.soinside.com 2019 - 2024. All rights reserved.