当前位置: 首页 > 知识库问答 >
问题:

OpenGL:将FBO的深度纹理绑定到计算着色器

萧树
2023-03-14

我一直在尝试渲染到一个FBO,并将两个FBO渲染到屏幕上,但在合并两个FBO时进行深度测试失败。我尝试使用计算着色器合并纹理,但无法读取深度纹理的值(所有值都是值1,但渲染到FBO时深度测试有效)。有人知道我做错了什么,或者知道其他方法来合并两个FBO吗?

以下是我创建FBO的方式:

struct FBO {
    uint color;
    uint depth;
    uint fbo;
};
FBO createFBO(int width, int height) {
    FBO fbo;
    fbo.color = createFBOTexture(width, height, false);
    fbo.depth = createFBOTexture(width, height, true);
    fbo.fbo = generateFramebuffer(fbo.color, fbo.depth);

    return fbo;
}
uint createFBOTexture(int width, int height, bool isDepthBuffer) {
    uint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);

    if (isDepthBuffer)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
    else
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_FLOAT, NULL);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    int i = glGetError();
    if (i)
    std::cout << "Error while creating the FBO: " << gluErrorString(i) << '\n';

    return texture;
}
uint generateFrameBuffer(uint color, uint depth)
{
    int mipmapLevel = 0;

    //Generate FBO
    uint fbo;
    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);

    //Attatch textures to the FBO
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, mipmapLevel);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, mipmapLevel);

    //Error check
    int i = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (i != GL_FRAMEBUFFER_COMPLETE)
        std::cout << "ERROR: frambuffer is not ok, status: " << i << '\n';
    else {
        int i = glGetError();
        if (i)
            std::cout << "Error while creating the FBO: " << gluErrorString(i) << '\n';
    }
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    return fbo;
}

以下是我向FBO渲染的方式:

glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);

glBindFramebuffer(GL_FRAMEBUFFER, fbo_pointcloud.fbo);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawPointCloud(); //Here I draw points with the depreciated fixed pipeline
glFlush();

我尝试用glBindTexture绑定纹理(所有值均为1):

void MergeFrames::merge(TextureLoading::FBO tex0, TextureLoading::FBO tex1, GLuint result, int width, int height)
{
    glUseProgram(shader);

    //Bind depth textures
    glActiveTexture(GL_TEXTURE0+0);
    glBindTexture(GL_TEXTURE_2D, tex0.depth);
    glActiveTexture(GL_TEXTURE0+1);
    glBindTexture(GL_TEXTURE_2D, tex1.depth);

    //Bind color textures
    glBindImageTexture(2, tex0.color, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
    glBindImageTexture(3, tex1.color, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
    glBindImageTexture(4, result, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);

    //Dispatch the shader
    glDispatchCompute(ceilf(width / 16.0f), ceilf(height / 16.0f), 1);
}

计算着色器:

#version 430

uniform sampler2D depthTex0;
uniform sampler2D depthTex1;
uniform layout(rgba8) readonly image2D colorTex0;
uniform layout(rgba8) readonly image2D colorTex1;
uniform layout(rgba8) writeonly image2D mergedColor;

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

void main() {
    ivec2 ID = ivec2(gl_GlobalInvocationID.xy); 
    ivec2 size = imageSize(colorTex0);
    vec2 texCoords = vec2(float(ID.x)/float(size.x),float(ID.y)/float(size.y));

    float depths[2];
    vec4 colors[2];

    depths[0] = texture2D(depthTex0, texCoords).x;
    depths[1] = texture2D(depthTex1, texCoords).x;

    colors[0] = imageLoad(colorTex0, ID);
    colors[1] = imageLoad(colorTex1, ID);

    int i = int(depths[1] > depths[0]);
    imageStore(mergedColor, ID, colors[i]);
}

我已尝试使用glBindTexture绑定纹理(所有值均为0):

void MergeFrames::merge(TextureLoading::FBO tex0, TextureLoading::FBO tex1, GLuint result, int width, int height)
{
    glUseProgram(shader);

    glBindImageTexture(0, tex0.color, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
    glBindImageTexture(1, tex1.color, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
    glBindImageTexture(2, tex0.depth, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R16);
    glBindImageTexture(3, tex1.depth, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R16);
    glBindImageTexture(4, result, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);

    glDispatchCompute(ceilf(width / 16.0f), ceilf(height / 16.0f), 1);
}

计算着色器:

#version 430

uniform layout(rgba8) readonly image2D colorTex0;
uniform layout(rgba8) readonly image2D colorTex1;
uniform layout(r16) readonly image2D depthTex0;
uniform layout(r16) readonly image2D depthTex1;
uniform layout(rgba8) writeonly image2D mergedColor;

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

void main() {
    ivec2 ID = ivec2(gl_GlobalInvocationID.xy); 

    float depths[2];
    vec4 colors[2];

    colors[0] = imageLoad(colorTex0, ID);
    depths[0] = imageLoad(depthTex0, ID).x;

    colors[1] = imageLoad(colorTex1, ID);
    depths[1] = imageLoad(depthTex1, ID).x;

    int i = int(depths[1] < depths[0]);
    imageStore(mergedColor, ID, colors[i]);
}

这就是我绑定索引的方式(在我使用sampler2D而不是image2D的版本中,索引是不同的):

MergeFrames::MergeFrames()
{
    shader = OpenGL::compileComputeShader("MergeFrames.comp");

    glUseProgram(shader);

    glUniform1i(glGetUniformLocation(shader, "colorTex0"), 0);
    glUniform1i(glGetUniformLocation(shader, "colorTex1"), 1);
    glUniform1i(glGetUniformLocation(shader, "depthTex0"), 2);
    glUniform1i(glGetUniformLocation(shader, "depthTex1"), 3);
    glUniform1i(glGetUniformLocation(shader, "mergedColor"), 4);
}

共有1个答案

晏昀
2023-03-14

通过在渲染后将数据从深度纹理复制到格式为GL_RED的纹理,我使代码正常工作。

 类似资料:
  • 我是OpenGL的新手,在整理如何将纹理和着色器绑定到VBOs时遇到了困难。 我正在使用Cinder的纹理和着色器类。以下是我绘制方法的一部分: 在上面的代码中,如果我注释掉对mShader的调用。bind(),我的球体VBO将显示纹理(myImage)。我的着色器适用于普通(无纹理)形状,但当我在绘制任何带有包裹纹理的形状之前绑定着色器时,它会阻止纹理显示。 这是我使用的着色器的问题,还是我不理

  • 我想在FBO中加载两个纹理,其中一个纹理包含HDR图像,我的第一个目标是将图像从第一个纹理“复制”到第二个纹理(该纹理为空),并称为“下采样纹理”。 所以我创建FBO,加载我想用颜色_附件_0书写的纹理,并绑定它;然后初始化我的着色器程序并渲染一个四边形,其中包含我要在GL\u texture\u 0中读取的纹理。 然后我解开FBO并绑定“DownSamplingTex”,然后画一个四元组。 我不

  • 我在Mac OSX下工作,试图通过GLSL着色器在立方体上映射图像。 我显示立方体(以及图像,当它不通过着色器时)的方法是: 正如你所看到的,我正在检查,在这个测试中,是否有一个着色器应用到我的对象上(它是一个包装,效果非常好) 如果没有着色器,我只启用GL_纹理_坐标_数组,如果有,我尝试将图像绑定到着色器中的采样2D均匀。 我使用的着色器非常简单:它只显示纹理。我在Quartz Compose

  • 我需要处理许多只共享少数纹理的对象。手动定义和加载纹理一个接一个(如SO上的另一篇文章中所述)感觉不太对劲...尤其是因为WebGL中没有语句。 因此,我想将用于顶点的纹理作为顶点属性传递,并将该数字用作fragement着色器中某些“纹理数组”的索引。但是采样器上的OpenGL wiki(不是WebGL的完美参考,但我找到的那个)说: 取样器的变量只能用两种方式之一来定义。它可以定义为函数参数或

  • 我正在尝试将多个纹理绑定到片段着色器中的采样器。加载代码似乎运行良好。ATI的CodeXL显示正确加载的纹理。 但是,当我将模型的纹理绑定到活动纹理0和1时,我无法让它将值发送到我的着色器。当我将着色器统一标记为usampler2D并使用uvec4存储颜色时,就像我应该做的那样,因为我的纹理是以无符号字节提供的,我得到了一个全白色的模型。当我将着色器统一更改为sampler2D并使用vec4存储颜

  • 我在FBO中从渲染缓冲区切换到深度纹理。但它似乎不包含任何深度数据。如果我把这个纹理渲染成全屏的四边形,所有的东西都是黑色的。我非常确定纹理和FBO设置是好的。FBO已经完成,如果我清除了深度,让我们对格雷说: glClearDepth(0.5f); 然后我看到了斑点通道中的颜色,但没有看到几何渲染中的数据。 总之,这就是我创建纹理的方式: 其中intFmt是GL_DEPTH_component