3

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

我希望这种行为在使用多个帧缓冲区时起作用!如何合并两个帧缓冲区并在顶部渲染获胜的片段(深度测试)!基本上就像 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);
  }

}
4

3 回答 3

4

您将需要一个着色器来实现这一点。没有使用深度值进行 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 - 如何访问深度缓冲区值?- 或者:gl_FragCoord.z 与将深度渲染到纹理以了解如何访问深度纹理。

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

于 2017-11-28T22:34:58.843 回答
3

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

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

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

于 2017-11-28T22:15:43.323 回答
1

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

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

于 2017-11-28T22:20:32.623 回答