OpenGL 帧缓冲区颜色附件到计算着色器

Posted

技术标签:

【中文标题】OpenGL 帧缓冲区颜色附件到计算着色器【英文标题】:OpenGL Framebuffer ColorAttachment to Compute Shader 【发布时间】:2018-06-30 17:49:28 【问题描述】:

我想将自定义帧缓冲区的颜色附件放入计算着色器中以进行简单的图像处理,但我只得到黑屏。 这是我的示例代码

创建颜色附件

glGenFramebuffers(1, &this->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, this->fbo);
glGenTextures(1, &this->textureColorBuffer);
glBindTexture(GL_TEXTURE_2D, this->textureColorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, this->width(), this->height(), 0, 
GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 
this->textureColorBuffer, 0);

编译和链接着色器

cshader = glCreateShader(GL_COMPUTE_SHADER);
const char *csSrc[] = 
    "#version 440\n",
    "layout (binding = 0, rgba32f) uniform image2D destTex;\
     layout (binding = 1, rgba32f) uniform image2D sourceTex;\
     layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;\
     void main() \              
            vec4 texel;\
            ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);\
            texel = imageLoad(sourceTex, storePos);\
            texel = vec4(1.0) - texel;\
            imageStore(destTex, storePos, texel);\
    "
;
glShaderSource(cshader, 2, csSrc, NULL);
glCompileShader(cshader);


cshaderprogram = glCreateProgram();
glAttachShader(cshaderprogram, cshader);
glLinkProgram(cshaderprogram);

调用着色器并将纹理绘制到四边形。着色器是一个简单的颜色切换着色器,用于测试目的。

glUseProgram(cshaderprogram);
glUniform1i(0, 0);
glActiveTexture(GL_TEXTURE0);
glBindImageTexture(0, outputTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, 
GL_RGBA32F);


glActiveTexture(GL_TEXTURE1);
glBindImageTexture(0, textureColorBuffer, 0, GL_FALSE, 0, GL_READ_ONLY, 
GL_RGBA32F);
glUniform1i(1, 1);
glDispatchCompute(width() / 16, height() / 16, 1);

glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
screenProgram.bind();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindVertexArray(screenVao);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, outputTexture);
glDrawArrays(GL_TRIANGLES, 0, 6);

我能够正确地将 textureColorBuffer 渲染到四边形,并且可以写入纹理。我认为我不知道如何从帧缓冲区中读取的问题。

我希望你能帮助我。如果还有一些问题就问吧。

【问题讨论】:

【参考方案1】:

sourceTex的绑定点是1而不是0:

layout (binding = 1, rgba32f) uniform image2D sourceTex;

所以你必须将纹理绑定到图像单元 1

glBindImageTexture( 1, // <------- 1 instead of 0
    textureColorBuffer, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); 

注意,Images units 和 Texture units 是不同的东西。


当然,您也可以在计算着色器中使用纹理采样器制服。如果destTexsourceTex 大小相同,可以使用texelFetchgl_GlobalInvocationID 查找sourceTex

layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;

layout (binding = 0, rgba32f) uniform image2D destTex;
layout (binding = 0) uniform sampler2D sourceTex; 

void main()
       
    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);       

    vec4 texel = texelFetch(sourceTex, pos, 0);

    texel = vec4(1.0) - texel;
    imageStore(destTex, pos, texel);

在上面的 sn-p 中,destTex 使用图像单元 0,sourceTex 使用纹理单元 0。


对了,你确定要这样做吗

texel = vec4(1.0) - texel;

注意,如果texel的alpha通道为1.0,它将变得完全透明。

【讨论】:

又是一次绝对的大帮助。它现在工作。我犯了一些小错误,你向我展示并解释了如何解决这个问题。谢谢!

以上是关于OpenGL 帧缓冲区颜色附件到计算着色器的主要内容,如果未能解决你的问题,请参考以下文章

◮OpenGL-帧缓冲

Android OpenGLES3绘图 - 帧缓冲

获取最大数量的帧缓冲区颜色附件?

Opengl 和 Webgl:从附加到当前帧缓冲区的纹理中采样

打开 gl 计算着色器和帧缓冲区

OpenGL 帧缓冲区缺失面