我试图在我的简单OpenGL渲染器中实现PBR,并尝试使用多个照明过程,我使用每个灯光一个过程进行渲染,如下所示:
1-第一遍=深度
2秒传递=环境光
3- 3 ..N表示场景中的所有灯光。
我对过程3..n使用混合函数glBlendFunc(GL_ONE,GL_ONE),并在每个片段着色器的末尾执行伽马校正。
但是我仍然有一个输出图像的问题,它看起来很嘈杂,特别是当我使用纹理贴图的时候。
这些步骤有什么问题吗?或者这个过程有什么改进吗?
发布于 2018-05-21 21:49:20
所以基本上,你计算的是
f(x) = a^gamma + b^gamma + ...然而,您真正想要的(正如@NicolBolas已经在评论中指出的那样)是
g(x) = (a + b + ...)^gamma现在,f(x)和g(x)只有在像gamma=1这样无用的情况下才是平等的。你不能简单地以这种方式附加分解像power这样的非线性函数。
正确的解决方案是在线性空间中将所有东西混合在一起,然后对每个光源的线性贡献的总和进行伽马校正。
然而,实现这一点将导致几个技术问题。首先也是最重要的是,标准的每通道8位不足以存储线性颜色值。使用这种用于累加步骤的格式将导致强烈可见的色带伪影。有两种方法可以解决这个问题:
GL_RGBA16F似乎是一种特别好的格式。由于使用PBR照明模型,因此还可以使用0,1以外的颜色值,并且在最终过程中应用适当的色调贴图,而不是简单的gamma校正。请注意,虽然您可能不需要alpha chanell,但这里仍使用RGBA格式,RGB格式根本不是GL规范所要求的颜色缓冲格式,因此它们可能不支持仍为8位/分量格式的数据,伽马校正。这里的关键是,混合仍然必须在线性空间中完成,因此目标帧缓冲区颜色值必须在混合之前重新线性化。这可以通过使用GL_SRGB8_ALPHA8格式的帧缓冲区并启用GL_FRAMEBUFFER_SRGB来实现。在这种情况下,图形处理器将在将碎片颜色写入帧缓冲区时自动应用标准sRGB gamma校正(当前您的片段着色器正在执行此操作),但在访问这些值时也会导致sRGB线性化,包括用于混合。OpenGL 4.6 core profile spec在"17.3.6.1混合方程“一节中陈述:如果启用了FRAMEBUFFER_SRGB,并且与目标缓冲区对应的帧缓冲区附件的FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING值为SRGB (请参见9.2.3节),则R、G和B目标颜色值(从定点转换为浮点之后)将被视为针对sRGB颜色空间进行了编码,因此必须在将其用于混合之前进行线性化。每个R、G和B组件的转换方式与8.24节中为sRGB纹理组件所述的方式相同。
方法1将是更通用的方法,而方法2有几个缺点:
但是,方法2也有优势:
GL_FRAMEBUFFER_SRGB就足以实现这一点。https://stackoverflow.com/questions/50426929
复制相似问题