【问题标题】:Render FBO to screen taking into account Depth在考虑深度的情况下将 FBO 渲染到屏幕
【发布时间】:2017-01-28 00:14:41
【问题描述】:

目标:OpenGL ES 3.0

假设我的默认帧缓冲区(屏幕)已经包含我渲染的部分场景;它的颜色和深度缓冲区包含有效数据。

现在假设我已经将场景的另一部分渲染到中间 FBO 'fbo1'。它的颜色数据保存在纹理“mColor”中,该纹理附加到 fbo1.COLOR0 附件,其深度保存在另一个纹理“mDepth”中,该纹理“mDepth”附加到另一个 FBO“fbo2”的 DEPTH 附件中。

现在我想将 mColor 渲染到屏幕上,同时考虑到 mDepth 的深度。我知道如何将仅包含颜色数据的纹理渲染到屏幕上,但考虑到 mDepth,我不知道该怎么做。

本质上,当我们将使用 mColor 纹理的 Quad 渲染到屏幕时,我们需要比较屏幕的深度缓冲区,而不是与 Quad 的深度,而是与 mDepth 的深度。该怎么做?

【问题讨论】:

    标签: opengl-es depth-buffer


    【解决方案1】:

    如果您要拆分管道并在多个通道中渲染 FBO0,并与屏幕外渲染交错,那么简单的答案就是“您做错了”。

    您正在强制 GPU 写出和回读您的中间状态,这非常低效,尤其是在具有基于 tile 架构的移动设备上。

    首先渲染每个离屏通道,然后渲染窗口表面 (FBO0) 以在单个通道中完成。

    我们需要比较屏幕的深度缓冲区,而不是与 Quad 的深度,而是与 mDepth 的深度。该怎么做?

    从深度纹理加载深度值,并将该值分配给片段着色器中的gl_FragDepth。但是,这将强制您的所有片段进行后期 zs 深度更新,与在 early-zs 使用真实三角形 z 值相比,这非常慢,因为您必须在确定是否需要保留片段之前运行着色器或不。所以,根据上面我建议重新设计你的渲染管道,这样你就不需要这样做了......

    【讨论】:

    • 我明白了。这就是我真正在做的事情:首先我渲染我的大部分场景。然后,在 N 次传递中,我将需要一些后处理的每个对象渲染到屏幕外缓冲区。我计算对象将在屏幕上结束的位置(它的网格非常简单),将其渲染为足够大的 FBO,然后对对象应用后处理,然后我面临问题中描述的问题:如何将其合并到屏幕上。我认为对每个对象进行后处理会更简单,因为这样,例如,如果我对对象进行 BLUR,我就不必担心更近的对象会“爬行”到我的 BLUR 中。
    • 模糊自然意味着某种形式的“模糊边缘” - 这是它的一半 - 所以在某些时候你将不得不解决“蠕变”。您只是将痛苦推迟到管道的稍后阶段,您并没有让它消失。
    • 不不,我已经实施了您的建议,并且效果很好 - 即,如果我们有一个更近的、未模糊的物体部分地阻挡了一个更远的、模糊的物体,那么越近的物体仍然非常清晰。为了在没有每个对象后处理的情况下实现这种效果(即,如果我必须一次性对整个场景进行后处理),我必须使用模板来标记另一个对象,然后通过模板测试应用模糊,但要考虑考虑 DEPTH(靠近与较近对象边界的较远对象的像素不会受到较近对象的像素的影响!)。
    • 即使我考虑了深度并在“更近”对象的第一个像素出现时停止模糊,效果也不一样——我永远无法影响那些模糊的被遮挡的另一个对象的那部分像素,因此当两个对象四处移动时,模糊会在对象之间的边界附近发生不自然的变化。
    【解决方案2】:

    您可以将 FBO 的深度用作纹理。当您绘制 FBO 的内容时,您会从 FBO 的深度纹理中手动绘制颜色通道并写入 gl_FragDepth。之后,您可以在启用适当深度测试的情况下绘制所有其他场景内容。

    【讨论】:

    • 嗯...我不太明白。当然,当我将带有 mColor 的 Quad 纹理渲染到屏幕上时,在我的片段着色器中我可以写入 gl_FragDepth 并将其设置为“mDepth”的内容,但这并没有给我任何东西。 DEPTH 测试已经在片段着色器之前运行,并将屏幕的深度与从 Quad 的 4 个角的线性插值得到的深度进行比较,而不是与 mDepth。这就是问题所在。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-21
    • 1970-01-01
    • 2022-10-22
    • 1970-01-01
    • 1970-01-01
    • 2017-03-31
    • 1970-01-01
    相关资源
    最近更新 更多