主要是参考毛星云大佬对BRDF的解释
还有就是unity内置管线中的BRDF相关代码:
整个BRDF和PBR系列整理的很碎,主要是记录的一些自己忽略的点,
网上整体讲解BRDF的很多,但是讲到下面的知识的很少,或者说大佬已经讲了我没理解==
权当自己的笔记,谨慎参考~~
(1)BRDF公式中 分母的消失??!!!
隐式遮蔽函数:
隐式遮蔽函数 (The Implicit Masking Function)可以和Specular的分母校正因子4(n·l)(n·v)相消为1,虽然不是严格基于物理,但具有非常好的性价比。
重要:这样在计算的时候,就通了!!!!!
在计算高光项的时候,
最后的公式就变成 : f(I,V) = F * V * D
(2)关于grazingTerm的理解: grazingTerm 影响间接高光的反射
(光滑度和金属度的和 =》 决定 grazingTerm的大小,而grazingTerm的大小 影响 间接高光的反射)
--漫反射率 -- metallic: 金属度
half oneMinusReflectivity = OneMinusReflectivityMetallic(metallic);
half grazingTerm = saturate(smoothness + (1-oneMinusReflectivity));
smoothness : 光滑度
oneMinusReflectivity : 漫反射率
因此:在金属工作流的模式下,
反射率只和金属度有关: 反射率和金属度成 正比
金属度 metallic : 0 1
漫反射率 OneMinusReflectivity: 0.96 0
金属度 0, 反射率 0.04;
金属度 1, 反射率 1;
最后附上BRDF计算中用的数学模型对应的代码:
// 阴影遮蔽函数
// Sq(x) = x * x;
// Precompute part of lambdaV
real GetSmithJointGGXPartLambdaV2(real NdotV, real roughness)
{
real a2 = Sq(roughness);
return sqrt(max(0.002,-NdotV * a2 + NdotV) * NdotV + a2);
}
real V_SmithJointGGX2(real NdotL, real NdotV, real roughness, real partLambdaV)
{
real a2 = Sq(roughness);
real lambdaV = NdotL * partLambdaV;
real lambdaL = NdotV * sqrt(max(0.002,(-NdotL * a2 + NdotL) * NdotL + a2));
//return 0.5 / (NdotL + lambdaL);
return 0.5 / max(0.002,lambdaV + lambdaL);
}
real V_SmithJointGGX2(real NdotL, real NdotV, real roughness)
{
real partLambdaV = GetSmithJointGGXPartLambdaV2(NdotV, roughness);
return V_SmithJointGGX2(NdotL, NdotV, roughness, partLambdaV);
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
//---------------------------------------------------------------------
//迪士尼的diffuse模型
half StDisneyDiffuse(half NdotV, half NdotL, half LdotH, half perceptualRoughness)
{
half fd90 = 0.5 + 2 * LdotH * LdotH * perceptualRoughness;
// Two schlick fresnel term
half lightScatter = (1 + (fd90 - 1) * Pow5(1 - NdotL));
half viewScatter = (1 + (fd90 - 1) * Pow5(1 - NdotV));
return lightScatter * viewScatter;
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
//---------------------------------------------------------------------
// 法线分布函数:
real D_GGXNoPI(real NdotH, real roughness)
{
real a2 = Sq(roughness);
real s = (NdotH * a2 - NdotH) * NdotH + 1.0;
// If roughness is 0, returns (NdotH == 1 ? 1 : 0).
// That is, it returns 1 for perfect mirror reflection, and 0 otherwise.
return SafeDiv(a2, s * s);
}
real D_GGX(real NdotH, real roughness)
{
return INV_PI * D_GGXNoPI(NdotH, roughness);
}