【问题标题】:Forward rendering multiple rendering passes前向渲染多个渲染通道
【发布时间】:2018-05-19 15:40:13
【问题描述】:

我正在尝试在我的简单 OpenGL 渲染器中实现 PBR,并尝试使用多个光照通道,我使用每个光照一个通道进行渲染,如下所示:

1- 第一遍 = 深度

2- 第二遍 = 环境

3- [3 .. n] 用于场景中的所有灯光。

我将混合函数 glBlendFunc(GL_ONE, GL_ONE) 用于通道 [3..n],并且在每个片段着色器的末尾进行 Gamma 校正。

但我的输出图像仍然存在问题,当我使用纹理贴图时,它看起来很嘈杂。

这些步骤有什么问题吗?或者这个过程有什么改进?

【问题讨论】:

  • "我在每个片段着色器的末尾进行 Gamma 校正。" 你不应该这样做。伽玛校正将线性值转换为非线性的伽玛空间值。您不应该在伽马空间中进行混合;混合只能应用于线性值。
  • 所以@NicolBolas 你有解决这个问题的想法吗?好像我没有进行伽玛校正一样,输出图像很暗。
  • 最后做一次伽玛校正,很明显。我看不出有任何理由让结果变得嘈杂。你能分享一个示例图像吗?您的渲染器中没有任何随机因素,对吧?
  • 您可以做的一些改进是将深度预传递与环境传递相结合,使其成为一次传递。接下来根据材料将材料放入队列中。所以你有不透明的物体,投射阴影的物体和透明的物体。然后为最后渲染透明队列的所有灯光渲染每个队列。

标签: opengl glsl rendering


【解决方案1】:

所以基本上,你计算的是

f(x) = a^gamma + b^gamma + ...

但是,您真正想要的(正如 @NicolBolas 在 cmets 中所指出的那样)是

g(x) = (a + b + ...)^gamma

现在f(x)g(x) 只会在像gamma=1 这样相当无用的情况下彼此相等。你根本无法以这种方式对像幂这样的非线性函数进行加法分解。

正确的解决方案是在线性空间中将所有内容混合在一起,然后对每个光源的线性贡献的总和进行伽马校正。

但是,实现这一点会导致一些技术问题。首先,标准的每通道 8 位不够精确,无法存储 linear 颜色值。将这种格式用于累积步骤将导致强烈可见的色带伪影。有两种方法可以解决这个问题:

  1. 为累积帧缓冲区使用更高的每通道比特格式。您将需要一个单独的 gamma 校正通道,因此您需要通过 FBO 设置渲染到纹理。 GL_RGBA16F 似乎是一种特别好的格式。由于您使用的是 PBR 照明模型,因此您还可以使用 [0,1] 之外的颜色值,而不是简单的伽马校正,而是在最终通道中应用适当的色调映射。请注意,虽然您可能不需要 alpha chanell,但仍使用 RGBA 格式,RGB 格式根本不是 GL 规范要求的颜色缓冲区格式,因此它们可能不受普遍支持。

  2. 仍然以每分量 8 位格式存储数据,伽马校正。这里的关键是混合仍然必须在线性空间中完成,因此目标帧缓冲区颜色值必须在混合之前重新线性化。这可以通过使用GL_SRGB8_ALPHA8 格式的帧缓冲区并启用GL_FRAMEBUFFER_SRGB 来实现。在这种情况下,GPU 将在将片段颜色写入帧缓冲区时自动应用标准 sRGB 伽马校正(目前您的片段着色器会这样做),但在访问这些值(包括混合)时,它也会导致 sRGB 线性化。 OpenGL 4.6 core profile spec 在“17.3.6.1 混合方程”部分中声明:

    如果启用FRAMEBUFFER_SRGB 并且帧缓冲附件的FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 的值对应 到目标缓冲区是SRGB(参见第 9.2.3 节)、RGB 目标 颜色值(从定点转换为浮点后)被认为是 为 sRGB 颜色空间编码,因此必须在它们之前线性化 用于混合。每个RGB 组件都以相同的方式转换 在 8.24 节中描述了 sRGB 纹理组件。

方法 1 将是更通用的方法,而方法 2 有几个缺点:

  • 线性化/去线性化执行多次,可能会浪费一些 GPU 处理能力
  • 由于仍然只使用8位整数,整体质量会较低。在每个混合步骤之后,结果都会四舍五入到下一个可表示的数字,因此您会得到更多的量化噪声。
  • 您仍然受限于 [0,1] 中的颜色值,无法(轻松)进行更有趣的色调映射和 HDR 渲染效果

不过,方法 2 也有优势:

  • 您不需要单独的最终伽马校正通道
  • 如果您的平台/窗口系统确实支持 sRGB 帧缓冲区,您可以直接为您的窗口创建一个 sRGB 像素格式/视觉对象,根本不需要任何渲染到纹理的步骤。基本上,请求 sRGB 帧缓冲区并启用 GL_FRAMEBUFFER_SRGB 就足以完成这项工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-11
    • 1970-01-01
    • 2016-06-22
    • 1970-01-01
    • 2018-01-03
    • 2022-08-03
    • 2023-02-23
    • 2020-11-15
    相关资源
    最近更新 更多