Opengl 深度测试后将两个单独的帧缓冲区合并到默认帧缓冲区

Opengl 深度测试后将两个单独的帧缓冲区合并到默认帧缓冲区,opengl,framebuffer,depth-buffer,depth-testing,Opengl,Framebuffer,Depth Buffer,Depth Testing,我有两个帧缓冲区,我正在渲染两个不同的对象。使用默认帧缓冲区时,两个对象都在同一个帧缓冲区上渲染 我希望这种行为在使用多个帧缓冲区时起作用!如何合并两个帧缓冲区并在顶部渲染获胜片段(深度测试)!基本上像一个Photoshop图层合并,但深度测试 我甚至将一个帧缓冲区切换到默认帧缓冲区,但我不知道如何将两个帧缓冲区合并在一起 注意:我有一个颜色和深度附件到帧缓冲区 编辑: 好的。除了一件小事之外,我几乎已经设置好了渲染到四边形工作模式。我的颜色buff使用统一采样器正确发送到着色器,但我的深度值始

我有两个帧缓冲区,我正在渲染两个不同的对象。使用默认帧缓冲区时,两个对象都在同一个帧缓冲区上渲染

我希望这种行为在使用多个帧缓冲区时起作用!如何合并两个帧缓冲区并在顶部渲染获胜片段(深度测试)!基本上像一个Photoshop图层合并,但深度测试

我甚至将一个帧缓冲区切换到默认帧缓冲区,但我不知道如何将两个帧缓冲区合并在一起

注意:我有一个颜色和深度附件到帧缓冲区

编辑:

好的。除了一件小事之外,我几乎已经设置好了渲染到四边形工作模式。我的颜色buff使用统一采样器正确发送到着色器,但我的深度值始终从深度缓冲区返回“0”

这就是我在帧缓冲区中设置深度缓冲区的方式

  glGenFramebuffers(1, &_fbo);
  glBindFramebuffer(GL_FRAMEBUFFER, _fbo);

  glGenTextures(1, &_cbo);
  glGenTextures(1, &_dbo);

  {
    glBindTexture(GL_TEXTURE_2D, _cbo);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dim.x, dim.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);

  }

  {
    glBindTexture(GL_TEXTURE_2D, _dbo);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, dim.x, dim.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
  }

  glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _cbo, 0);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _dbo, 0);
这就是我如何将均匀采样器发送到着色器的方式

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,cbo1);
glUniform1i(glGetUniformLocation(QuadShader.Program, "color1"),0);


glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, cbo2);
glUniform1i(glGetUniformLocation(QuadShader.Program, "color2"), 1);

glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, dbo1);
glUniform1i(glGetUniformLocation(QuadShader.Program, "depth1"), 2);


glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, dbo2);
glUniform1i(glGetUniformLocation(QuadShader.Program, "depth2"), 3);

glBindVertexArray(BgVao);
glDrawArrays(GL_TRIANGLES, 0, 6);
这是我的着色器的外观:

uniform sampler2D color1;
uniform sampler2D color2;
uniform sampler2D depth1;
uniform sampler2D depth2;

out vec4 FragColor;

void main()
{
  ivec2 texcoord = ivec2(floor(gl_FragCoord.xy));

  vec4 depth1 = texelFetch(depth1, texcoord,0);
  vec4 depth2 = texelFetch(depth2, texcoord,0);

  if(depth1.z > depth2.z)
  {
    FragColor = texelFetch(color1, texcoord, 0);
  }
  else
  {
   FragColor = texelFetch(color2, texcoord, 0);
  }

}

Blitting永远不会使用深度测试,因此必须使用全屏着色器过程来组合两个帧缓冲区。有两种选择:

  • 将两个帧缓冲区合并为第三个帧缓冲区。这要求两个输入FBO的颜色附件和深度附件都是纹理。然后从颜色缓冲区和深度纹理渲染全屏四边形和采样。基本上,您可以在着色器中手动执行深度测试,通过比较两个深度来确定使用哪一个颜色值作为片段的最终输出颜色

  • 使用真实深度测试将一个帧缓冲区组合到另一个帧缓冲区中。在这种情况下,只有一个FBO必须使用纹理,另一个FBO可以使用renderbuffers或窗口系统提供的缓冲区。您只需渲染全屏四元体,这一次仅从一个输入FBO采样深度和颜色纹理,并在启用深度测试的情况下渲染到输出FBO。您只需将颜色值设置为片段着色器的输出,并将深度值另外输出到
    gl\u FragDepth


  • 对于使用两个帧缓冲区的颜色数据和两个帧缓冲区的深度数据的片段着色器,这应该是可能的,并通过为每个片段计算与赢得深度测试的片段对应的纹理来填充每个像素

    #version 430
    
    layout(location = 0) in vec2 tex_coord;
    
    layout(binding = 0) uniform sampler2D color_texture_1;
    layout(binding = 1) uniform sampler2D color_texture_2;
    layout(binding = 2) uniform sampler2D depth_texture_1;
    layout(binding = 3) uniform sampler2D depth_texture_2;
    
    layout(location = 0) out vec4 fragment_color;
    
    void main() {
        float depth_1 = texture(depth_texture_1, tex_coord).z;
        float depth_2 = texture(depth_texture_2, tex_coord).z;
        if(!/*check to verify *something* was rendered here in either framebuffer*/)
            discard;
        else {
            if(depth_1 > depth_2) //I'm pretty sure positive z values face the user
                fragment_color = texture(color_texture_1, tex_coord);
            else
                fragment_color = texture(color_texture_2, tex_coord);
        }
    }
    
    您将渲染一个(大概是全屏)四边形,使用带有此片段着色器的穿透顶点着色器,并附加相应的纹理


    我不知道你的深度纹理是什么格式;我的假设是,它包含表示单个碎片坐标的向量,z坐标包含其深度。如果不是这样,您需要进行调整。

    您需要一个着色器来实现这一点。没有使用深度值进行blit的内置方法。这里有一种结合两个FBO内容的方法

    顶点着色器(假设从(-1,-1)到(1,1)绘制四元体)

    像素着色器可能如下所示:

    uniform sampler2D Color0;
    uniform sampler2D Color1;
    uniform sampler2D Depth0;
    uniform sampler2D Depth1;
    
    in vec2 TexCoords;
    layout(location = 0) out vec4 FragColor;
    
    void main()
    {
        ivec2 texcoord = ivec2(floor(gl_FragCoord.xy));
        float depth0 = texelFetch(Depth0, texcoord, 0).r;
        float depth1 = texelFetch(Depth1, texcoord, 0).r;
    
        // possibly reversed depending on your depth buffer ordering strategy
        if (depth0 < depth1) {
            FragColor = texelFetch(Color0, texcoord, 0);
        } else {
            FragColor = texelFetch(Color1, texcoord, 0);
        }
    }
    
    0;
    均匀取样器2D颜色1;
    均匀采样深度0;
    均匀取样器2D深度1;
    在vec2-TexCoords中;
    布局(位置=0)输出vec4 FragColor;
    void main()
    {
    ivec2 texcoord=ivec2(地板(gl_FragCoord.xy));
    浮动深度0=texelFetch(深度0,texcoord,0).r;
    浮子深度1=texelFetch(深度1,texcoord,0).r;
    //根据深度缓冲区排序策略,可能会反转
    如果(深度0<深度1){
    FragColor=texelFetch(Color0,texcoord,0);
    }否则{
    FragColor=texelFetch(Color1,texcoord,0);
    }
    }
    
    有关如何访问深度纹理,请参见


    请注意,我在这里使用
    texelFetch()
    ,因为线性插值深度值不会给出有效的结果。

    Hi Bernie。谢谢你的帮助。除了深度返回“0”之外,它基本上正常工作。我用代码编辑了我的问题。请看一看!我看不出你的代码有什么问题。渲染到FBO时,深度测试或深度写入可能已关闭?这可以解释0的深度值。由于所有深度值==0,您能否确认在合成后获得
    Color1
    的输出?是的,您是对的!我根据depthvalues=0的<>符号获取color1或color2的值。在使用glEnable(GL_depth_TEST)绑定帧缓冲区之后,我立即启用深度测试。我还需要做些什么吗?这意味着深度写入可能不会发生。在渲染到FBO时,确保您具有
    glEnable(GL_深度测试)
    glDepthMask(GL_真实)
    glDepthRange(0,1)
    。您还可以尝试使用
    glClearDepth(1.0)
    glClear()
    将FBO的一个深度缓冲区清除为一个值,然后查看是否得到与0不同的值。嘿,伯尼,显然我需要将深度比较改为这个值。if(depth1.rdepth2.z){}。我现在工作得很好!顺便说一句,我应该把这个作为答案吗?谢谢你!我已经准备好四元渲染设置,除了深度值都为零!你能用代码看一下编辑过的问题吗!谢谢你的帮助!谢谢你的帮助!我已经编辑了我的问题!请看一看!
    uniform sampler2D Color0;
    uniform sampler2D Color1;
    uniform sampler2D Depth0;
    uniform sampler2D Depth1;
    
    in vec2 TexCoords;
    layout(location = 0) out vec4 FragColor;
    
    void main()
    {
        ivec2 texcoord = ivec2(floor(gl_FragCoord.xy));
        float depth0 = texelFetch(Depth0, texcoord, 0).r;
        float depth1 = texelFetch(Depth1, texcoord, 0).r;
    
        // possibly reversed depending on your depth buffer ordering strategy
        if (depth0 < depth1) {
            FragColor = texelFetch(Color0, texcoord, 0);
        } else {
            FragColor = texelFetch(Color1, texcoord, 0);
        }
    }