【问题标题】:Merging two separate framebuffers onto default framebuffer after depth testing深度测试后将两个单独的帧缓冲区合并到默认帧缓冲区
【发布时间】:2018-05-12 12:09:05
【问题描述】:

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

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

我已经将单个帧缓冲区传送到默认帧缓冲区,但我不知道如何将两个帧缓冲区合并在一起!

注意:我对帧缓冲区有颜色和深度附件。

编辑:

好的。除了一件小事外,我几乎已经设置了渲染到四边形的工作。我的颜色缓冲区使用统一采样器正确发送到着色器,但我的深度值始终从深度缓冲区返回“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);
  }

}

【问题讨论】:

    标签: opengl framebuffer depth-buffer depth-testing


    【解决方案1】:

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

    顶点着色器(假设从 (-1,-1) 到 (1,1) 绘制一个四边形)

    layout(location = 0) in vec4 Position;
    
    void main()
    {
        // Snap the input coordinates to a quad with it lower-left at (-1, -1, 0)
        // and its top-right at (1, 1, 0)
        gl_Position = vec4(sign(Position.xy), 0.0, 1.0);
    }
    

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

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

    另请参阅OpenGL - How to access depth buffer values? - Or: gl_FragCoord.z vs. Rendering depth to texture,了解如何访问深度纹理。

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

    【讨论】:

    • 你好,伯尼。谢谢你的帮助。除了深度返回'0'之外,我大部分时间都在工作。我已经用代码编辑了我的问题。请看一看!
    • 我看不出你的代码有什么问题。渲染到 FBO 时,深度测试或深度写入是否已关闭?这可以解释 0 的深度值。您能否确认在合成后得到 Color1 的输出,因为所有深度值 == 0?
    • 是的,你是对的!我根据深度值 = 0 的 符号获得 color1 或 color2 的值。我在使用 glEnable(GL_DEPTH_TEST) 绑定帧缓冲区后立即启用深度测试。我还应该做些什么吗?
    • 这意味着深度写入可能不会发生。确保你有glEnable(GL_DEPTH_TEST)glDepthMask(GL_TRUE)glDepthRange(0, 1) 渲染到你的 FBO 时。您还可以尝试使用 glClearDepth(1.0)glClear() 将 FBO 的深度缓冲区之一清除为一个值,看看您是否得到不同于 0 的值。
    • 嘿伯尼,显然我需要将深度比较更改为此。 if(depth1.r depth2.z){}。我现在工作正常!顺便说一句,我应该输入这个作为答案吗?
    【解决方案2】:

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

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

    2. 您使用真实深度测试将其中一个帧缓冲区合成到另一个帧缓冲区中。在这种情况下,只有一个 FBO 必须使用纹理,另一个可以使用渲染缓冲区或窗口系统提供的缓冲区。您只需要渲染一个全屏四边形,这次仅从一个输入 FBO 对深度和颜色纹理进行采样,然后在启用深度测试的情况下渲染到输出 FBO。您只需将颜色值设置为片段着色器的输出,并将深度值额外输出到gl_FragDepth

    【讨论】:

    • 感谢您的帮助!我已经编辑了我的问题!请看一看!
    【解决方案3】:

    这应该可以通过片段着色器实现,该着色器使用来自两个帧缓冲区的颜色数据和来自两个帧缓冲区的深度数据,并通过为每个片段评估与赢得深度测试的片段对应的纹理来填充每个像素。

    #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 坐标包含它的深度。如果不是这种情况,则需要进行调整。

    【讨论】:

    • 谢谢希瑞玛!我已经准备好了四边形渲染设置,除了深度值都为零!您能否用代码看一下已编辑的问题!感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-27
    相关资源
    最近更新 更多