GLSL PBS 实现,奇怪的着色器行为

Posted

技术标签:

【中文标题】GLSL PBS 实现,奇怪的着色器行为【英文标题】:GLSL PBS implementation, weird shader behaviour 【发布时间】:2015-08-18 09:40:53 【问题描述】:

我正在使用 Cook-Torrance 镜面反射 BRDF + Disney 的漫反射 BRDF 光模型,如果单独应用,它们可以正常工作。不幸的是,如果我尝试将它们结合起来,就会发生一些奇怪的事情: 漫反射光照贴图如下所示: 镜面光照贴图(注意地形边缘的伪影):

生成的光照贴图是这样计算的:

float result = Fr + Fd;

其中 Fd 是漫反射 BRDF 组件,Fr 是镜面反射 BRDF 组件。

为什么它会在生成的光照贴图上出现这样的伪影?

我在想产生的光强度超出范围 [0;1],检查我是否修改了代码如下:

return result <= 1.0 ? result : 1.0;

生成的光照贴图:

如您所见,现在所有伪影的强度都为 1.0(它们显然超出 [0;1] 范围),但如果高光贴图包含零,为什么还会出现这种情况?

完整的着色器代码:Pastebin

【问题讨论】:

似乎很难解释。只有一次我从着色器中看到过这样的奇怪结果,它是由一些未定义的数学引起的,这些数学导致 NaN 以奇怪的方式传播和破坏东西。也许看看所有的 pow 函数,并确保第一个参数不能为负数,方法是临时修改 abs/max/saturate 或所有这些函数(线 pow( pow(dotNH, 2.0) * (m_alpha - 1.0) + 1.0 , 2.0));例如可能有负数)。如果没有得到它,我会尝试简化 @Columbo 谢谢。 N和L的点积为0,除以零误差。我添加了 abs 函数作为修补程序。 【参考方案1】:

正如@Columbo 提到的,这是 NaN 异常(引发除以零的原因),这导致了奇怪的着色器行为。我稍微修改了代码:

float F_Schlick (in float f0, in float f90, in float u)

    return f0 + ( f90 - f0 ) * pow(clamp(1.0 - u, 0.0, 1.0), 5.0); //line 34

点积应该大于零:

float dotNV = abs(dot(N, V));
float dotNL = abs(dot(N, L));

The final shader code

【讨论】:

以上是关于GLSL PBS 实现,奇怪的着色器行为的主要内容,如果未能解决你的问题,请参考以下文章

为什么我在GLSL着色器中看到这些混合工件?

带有 Blinn-Phong GLSL 着色器、点光源的奇怪结果

GLSL-片段着色器不同部分的精度不同

GLSL 计算着色器闪烁块/正方形伪影

使用制服时 Xamarin OpenGL 片段着色器的奇怪行为

如何在 C++ 中为 GLSL 片段着色器实现 iGlobalTime?