我正在学习PBR和Unity标准着色器。GGX分布术语的巨大结果让我感到困惑。
Unity标准着色器使用GGX分布术语:
// I re-write it into C#
private float GGXTerm(float NdotH, float roughness)
{
float a2 = roughness * roughness;
float d = (NdotH * a2 - NdotH) * NdotH + 1.0f;
return a2 / (Mathf.PI * (d * d + 1e-7f));
}
这是一个让我困惑的问题:
- 将NdotH设置为1(视图方向正好在镜面反射的方向上(
- 将粗糙度设置为较低的值,如0.015
GGX项的结果为868.58123。这是一个非常大的数字,使最终的颜色远大于1。BRDF中的所有其他项都小于1。如果入射光只有1,那么这种大的反射能量似乎不符合能量守恒定律。我认为反射的能量肯定比入射的要小。
我知道我的理解一定有问题。感谢您的指导。
Khronos glTF示例查看器可能可以作为此处的附加参考。
看起来您已经实现了D()
项,Sample Viewer在BRDF着色器的第41-46行实现了该项。
但这并不是镜面反射的全部术语。该函数被进一步调用,作为函数BRDF_specularGGX在第108-115行的一部分。在用作镜面反射值之前,将得到的结果与其他几个项混合在一起。
glTF规范第B.3节对此有进一步的解读。