延迟渲染:在默认帧缓冲区中使用来自 Gbuffer 的深度缓冲区

Posted

技术标签:

【中文标题】延迟渲染:在默认帧缓冲区中使用来自 Gbuffer 的深度缓冲区【英文标题】:Deferred Rendering: Use depth buffer from Gbuffer in default framebuffer 【发布时间】:2014-08-07 12:17:17 【问题描述】:

我正在使用 C++ 和 OpenGL 制作延迟渲染应用程序。在完成几何和光通道之后,我想渲染一些粒子。但我需要对这些进行一些深度测试。所以我想做的是使用绑定到我的 GBuffer 的深度缓冲区在绘制到默认的 OpenGL 帧缓冲区时进行一些深度测试。

我像这样制作深度缓冲区/纹理并将其绑定到帧缓冲区/GBuffer

glGenTextures(1, &_depthTextureID);
glBindTexture(GL_TEXTURE_2D, _depthTextureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, _width, _height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, _depthTextureID, 0);

如何将 Gbuffer 深度缓冲区绑定到默认帧缓冲区,以便在几何通道上进行深度测试?

【问题讨论】:

【参考方案1】:

您不能直接将深度纹理用作默认帧缓冲区的深度缓冲区。我能想到的主要有两个选择:

    您可以使用glBlitFramebuffer() 将深度缓冲区从 FBO 复制到默认帧缓冲区。主要调用如下所示:

    glBindFramebuffer(GL_READ_FRAMEBUFFER, fboId);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    glBlitFramebuffer(0, 0, _width, _height, 0, 0, _width, _height,
                      GL_DEPTH_BUFFER_BIT, GL_NEAREST);
    

    如果您只需要深度测试,而不需要更新深度缓冲区,则在渲染到默认帧缓冲区的过程中,您可以简单地绑定深度纹理,并在片段着色器中对其进行采样。然后将采样的深度值与片段的传入深度值进行比较,并丢弃未通过深度测试的像素。或者你可以用sampler2DShadow类型的采样器进行采样,稍微更直接的得到深度比较结果。

【讨论】:

这两个选项你会选择哪一个? 我可能会从选项 1 开始。它很简单,实际上使用深度缓冲区进行渲染应该比在着色器中具有示例操作和分支更有效。唯一不受欢迎的方面是它涉及复制缓冲区。到处复制数据似乎总是很浪费。【参考方案2】:

您不能将创建的渲染缓冲区或纹理绑定到默认帧缓冲区。默认帧缓冲区是固定的。

但是您可以在将 GBuffer 渲染到默认帧缓冲区时将深度纹理复制到默认帧缓冲区,方法是在片段着色器中设置 gl_FragDepth

【讨论】:

那么在绘制光通的时候是不是必须读取深度纹理然后设置gl_FragDepth?那么这会影响默认帧缓冲区的深度缓冲区吗? 是的。这将复制深度缓冲区。

以上是关于延迟渲染:在默认帧缓冲区中使用来自 Gbuffer 的深度缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL 帧缓冲函数不能在单独的类中完全工作

我的帧缓冲区有啥问题?

与另一个单独的进程共享来自交换链后台缓冲区的 direct3d11 渲染帧作为纹理

Unity的延迟渲染(一)

从一个帧缓冲区读取到另一个帧缓冲区时出现问题

来自 OpenGL ES 帧缓冲区 (iOS) 的 CGImageRef