PBR中BRDF常用的各类法线分布函数、几何函数总结
顺序从老到新到实践拓展
一,法线分布函数(Normal Distribution Function,NDF)
1.1 各项同性NDF总结
1.1.1Blinn-Phong分布
D p ( h ) = 1 π α 2 ( n ⋅ h ) 2 α 2 − 2 D_{p}(h) = \frac{1}{πα^2}(n \cdot h)^{ \frac{2}{α^2} -2} Dp(h)=πα21(n⋅h)α22−2
float D_BlinnPhong(float NdotH, float Roughness2)
{
float n = 2 / Roughness2 - 2;
return (n+2) / (2*UNITY_PI) * pow( NdotH, n );
}
1.1.2 Beckmann分布
D b ( h ) = 1 π α 2 ( n ⋅ h ) 4 e x p ( n ⋅ h ) 2 − 1 α 2 ( n ⋅ h ) 2 D_{b}(h) = \frac{1}{πα^2(n \cdot h)^4}exp^{\frac{(n \cdot h)^2-1}{α^2(n \cdot h)^2}} Db(h)=πα2(n⋅h)41expα2(n⋅h)2(n⋅h)2−1
float D_Beckmann(float NdotH, float Roughness2)
{
float NdotH2 = NdotH * NdotH;
return exp( (NdotH2 - 1) / (Roughness2 * NdotH2) ) / ( UNITY_PI * Roughness2 * NdotH2 * NdotH2 );
}
1.1.3 GGX(Trowbridge-Reitz)分布
D G G X ( h ) = α 2 π ( ( n ⋅ h ) 2 ( α 2 − 1 ) + 1 ) 2 D_{GGX}(h) = \frac{α^2}{π((n \cdot h)^2(α^2 - 1)+1)^2} DGGX(h)=π((n⋅h)2(α2−1)+1)2α2
float D_GGX (float NdotH, float Roughness2)
{
float d = (Roughness2 - 1.0) * NdotH * NdotH + 1.0f;
return Roughness2 / (d * d * UNITY_PI);
}
- 以上三个分布是常用模型,效果对比如下,由于GGX高光扩散性更好因此被更广泛的使用
1.1.4 Generalized-Trowbridge-Reitz(GTR)分布
D G T R ( h ) = c ( ( n ⋅ h ) 2 ( α 2 − 1 ) + 1 ) γ D_{GTR}(h) = \frac{c}{((n \cdot h)^2(α^2 - 1)+1)^γ} DGTR(h)=((n⋅h)2(α2−1)+1)γc
γ=2时,GTR即GGX分布
γ=1时,GTR即Berry分布
float D_GTR1 (float NdotH, float Roughness2)
{
float d = (Roughness2 - 1.0) * NdotH * NdotH + 1.0f;
return (Roughness2-1) / ( d * log(Roughness2) * UNITY_PI);
}
1.2 各向异性NDF总结
at和ab分别是沿切线(tangent)方向t和副法线(binormal)方向b的粗糙度,如果at=ab,则回到了各向同性。
「注意网上shader一般会将切线方向t写作X,副法线(binormal)b方向写作Y」
1.2.1 Anisotropic Beckmann分布
D B a n i s o ( h ) = 1 π α x α y ( n ⋅ h ) 4 e x p ( − ( t ⋅ h ) 2 α x 2 + ( b ⋅ h ) 2 α y 2 ( n ⋅ h ) 2 ) D_{Baniso}(h) = \frac{1}{πα_xα_y(n \cdot h)^4} exp(- \frac{\frac{(t \cdot h)^2}{α_x^2} + \frac{(b \cdot h)^2}{α_y^2} }{(n \cdot h)^2}) DBaniso(h)=παxαy(n⋅h)41exp(−(n⋅h)2αx2(t⋅h)2+αy2(b⋅h)2)
float D_Beckmann_aniso( float at, float ab, float NoH, float3 H, float3 T, float3 B )
{
float ToH = dot( T, H );
float BoH = dot( B, H );
float d = - (ToH*ToH / (at*at) + BoH*BoH / (ab*ab)) / NoH*NoH;
return exp(d) / ( PI * at*ab * NoH * NoH * NoH * NoH );
}
1.2.2 Anisotropic GGX分布
D G G X a n i s o ( h ) = 1 π α x α y 1 ( ( t ⋅ h ) 2 α x 2 + ( b ⋅ h ) 2 α y 2 + ( n ⋅ h ) 2 ) 2 D_{GGXaniso}(h) = \frac{1}{πα_xα_y} \frac{1}{(\frac{(t \cdot h)^2}{α_x^2} + \frac{(b \cdot h)^2}{α_y^2} +(n \cdot h)^2)^2} DGGXaniso(h)=παxαy1(αx2(t⋅h)2+αy2(b⋅h)2+(n⋅h)2)21
float D_GGXaniso( float at, float ab, float NoH, float3 H, float3 T, float3 B )
{
float ToH = dot( T, H );
float BoH = dot( B, H );
float d = ToH*ToH / (at*at) + BoH*BoH / (ab*ab) + NoH*NoH;
return 1 / ( PI * at*ab * d*d );
}
1.2.3 各项异性参数化方法
上述各向异性是将t、b两个方向的粗糙度进行两次参数化,但有时也可以用其他参数化方法。
Disney
比如Disney用同性粗糙度和k_aniso组合(0-1),0.9将纵横比限制为10:1
k a s p e c t = 1 − 0.9 ∗ k a n i s o k_{aspect} = \sqrt{1-0.9*k_{aniso}} kaspect=1−0.9∗kaniso
α t = r 2 k a s p e c t α_t = \frac{r^2}{k_{aspect}} αt=kaspectr2
α b = r 2 k a s p e c t α_b = r^2k_{aspect} αb=r2kaspect
Sony Imageworks
允许任意程度的各向异性:
α t = r 2 ( 1 + k a n i s o ) α_t = r^2(1+k_{aniso}) αt=r2(1+kaniso)
α b = r 2 ( 1 − k a n i s o ) α_b =r^2(1-k_{aniso}) αb=r2(1−kaniso)
1.3 性能总结
「完全copy毛老师」
- Blinn-Phong不一定比GGX更省性能
- GGX计算可以用half带图float,但half计算存在两个问题
- 一是 1 − N o H 2 1-NoH^2 1−NoH2接近1时会出现浮点数取消(floating point cancellation)现象
- 二是NoH在1.0左右时精度不够.
可以通过拉格朗日恒等式 ∣ a × b ∣ 2 = ∣ a ∣ 2 ∣ b ∣ 2 − ( a ⋅ b ) 2 \vert a \times b\vert^2 = \vert a \vert^2\vert b \vert^2 - (a \cdot b)^2 ∣a×b∣2=∣a∣2∣b∣2−(a⋅b)2解决此问题:
带入n和h(单位向量)变为 ∣ n × h ∣ 2 = 1 − ( n ⋅ h ) 2 \vert n \times h\vert^2 = 1 - (n \cdot h)^2 ∣n×h∣2=1−(n⋅h)2,因此:
D G G X ( h ) = α 2 π ( ( n ⋅ h ) 2 ( α 2 − 1 ) + 1 ) 2 = α 2 π ( ∣ n × h ∣ 2 + α 2 ( n ⋅ h ) 2 ) 2 D_{GGX}(h) = \frac{α^2}{π((n \cdot h)^2(α^2 - 1)+1)^2}= \frac{α^2}{π(\vert n \times h\vert^2 + α^2(n \cdot h)^2)^2} DGGX(h)=π((n⋅h)2(α2−1)+1)2α2=π(∣n×h∣2+α2(n⋅h)2)2α2
half D_GGX (half NdotH, half Roughness2, half3 H, half3 N)
{
float3 NxH = cross(N, H);
float OneMinusNoHSqr = dot(NxH, NxH);
float d = OneMinusNoHSqr + NdotH * NdotH * Roughness2;
float p = Roughness2 / (d * d * UNITY_PI);
return min(p, 65504.0);
}
二,几何函数
2.1 Disney(2012)
G D i s n e y ( v ) = 2 ( n ⋅ v ) ( n ⋅ v ) + k 2 + ( 1 − k 2 ) ( n ⋅ v ) 2 其中 k = ( 0.5 + r o u g h n e s s 2 ) 2 G_{Disney}(v)= \frac{2(n \cdot v)}{(n \cdot v)+\sqrt{k^2+(1-k^2)(n \cdot v)^2}} 其中 k = (0.5+\frac{roughness}{2})^2 GDisney(v)=(n⋅v)+k2+(1−k2)(n⋅v)22(n⋅v)其中k=(0.5+2roughness)2
G ( i , o , h ) = G 1 ( i ) G 2 ( o ) G(i,o,h)= G_{1}(i)G_{2}(o) G(i,o,h)=G1(i)G2(o)
2.2 Schlick-GGX(2013)
G S c h l i c k G G X ( v ) = n ⋅ v ( n ⋅ v ) ( 1 − k ) + k 其中 k = ( α + 1 ) 2 8 G_{SchlickGGX}(v)= \frac{n \cdot v}{(n \cdot v)(1-k)+k} 其中 k = \frac{(α+1)^2}{8} GSchlickGGX(v)=(n⋅v)(1−k)+kn⋅v其中k=8(α+1)2
G ( i , o , h ) = G 1 ( i ) G 2 ( o ) G(i,o,h)= G_{1}(i)G_{2}(o) G(i,o,h)=G1(i)G2(o)
2.3 转向Smith联合遮蔽阴影函数(2014)
2.3.1 Frostbite的近似方案
G ( l , v ) 4 ∣ n ⋅ l ∣ ∣ n ⋅ v ∣ = 0.5 μ o α 2 + μ i ( μ i − α 2 μ i ) + μ i α 2 + μ o ( μ o − α 2 μ o ) \frac{G{}(l,v)}{4\vert{n \cdot l}\vert\vert n \cdot v\vert}= \frac{0.5}{μ_o\sqrt{α^2+μ_i(μ_i-α^2μ_i)}+μ_i\sqrt{α^2+μ_o(μ_o-α^2μ_o)}} 4∣n⋅l∣∣n⋅v∣G(l,v)=μoα2+μi(μi−α2μi)+μiα2+μo(μo−α2μo)0.5
其中 μ i = ( n ⋅ l ) + , μ o = ( n ⋅ v ) + μ_i = (n \cdot l)^+,μ_o = (n \cdot v)^+ μi=(n⋅l)+,μo=(n⋅v)+
2.3.2 UE4的近似方案
G ( l , v , h ) = 0.5 ( n ⋅ l ) ( ( n ⋅ v ) ( 1 − α 2 ) + α 2 ) + ( n ⋅ v ) ( ( n ⋅ l ) ( 1 − α 2 ) + α 2 ) G{}(l,v,h) = \frac{0.5}{(n \cdot l)((n \cdot v)(1-α^2)+α^2) + (n \cdot v)((n \cdot l)(1-α^2)+α^2)} G(l,v,h)=(n⋅l)((n⋅v)(1−α2)+α2)+(n⋅v)((n⋅l)(1−α2)+α2)0.5
其中 α = r o u g h n e s s α = roughness α=roughness
float Vis_SmithJointApprox( float NoL , float NoV,float a)
{
float a2 = a*a;
float Vis_SmithV = NoL * ( NoV * ( 1 - a2 ) + a2 );
float Vis_SmithL = NoV * ( NoL * ( 1 - a2 ) + a2 );
return 0.5 /( Vis_SmithV + Vis_SmithL );
}
2.3.3 Unity HDRP的近似方案
G ( l , v , h ) = 0.5 ( n ⋅ l ) ( ( n ⋅ v ) ( 1 − α ) + α ) + ( n ⋅ v ) ( 1 − α 2 ) ( n ⋅ l ) 2 + α 2 G{}(l,v,h) = \frac{0.5}{(n \cdot l)((n \cdot v)(1-α)+α) + (n \cdot v)\sqrt{(1-α^2)(n \cdot l)^2+α^2}} G(l,v,h)=(n⋅l)((n⋅v)(1−α)+α)+(n⋅v)(1−α2)(n⋅l)2+α20.5
其中 α = r o u g h n e s s α = roughness α=roughness
float V_SmithJointGGX(float NdotL, float NdotV, float roughness)
{
float a2 = roughness*roughness;
float lambdaV = NdotL * (NdotV * (1 - roughness) + roughness);
float lambdaL = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2);
return 0.5 / (lambdaV + lambdaL);
}
2.3.4 Google Filament的近似方案
G ( l , v , h ) = 0.5 ( n ⋅ l ) ( 1 − α 2 ) ( n ⋅ v ) 2 + α 2 + ( n ⋅ v ) ( 1 − α 2 ) ( n ⋅ l ) 2 + α 2 G{}(l,v,h) = \frac{0.5}{(n \cdot l)\sqrt{(1-α^2)(n \cdot v)^2+α^2} + (n \cdot v)\sqrt{(1-α^2)(n \cdot l)^2+α^2}} G(l,v,h)=(n⋅l)(1−α2)(n⋅v)2+α2+(n⋅v)(1−α2)(n⋅l)2+α20.5
其中 α = r o u g h n e s s α = roughness α=roughness
float G_SmithGGXCorrelated(float NoV, float NoL, float a)
{
float a2 = a * a;
float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);
float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);
return 0.5 / (GGXV + GGXL);
}
2.3.5 Respawn Entertainment的近似方案
G ( l , v ) 4 ∣ n ⋅ l ∣ ∣ n ⋅ v ∣ = 0.5 l e r p ( 2 ∣ n ⋅ l ∣ ∣ n ⋅ v ∣ , ∣ n ⋅ l ∣ + ∣ n ⋅ v ∣ , α ) \frac{G{}(l,v)}{4\vert{n \cdot l}\vert\vert n \cdot v\vert}= \frac{0.5}{lerp(2\vert{n \cdot l}\vert \vert{n \cdot v}\vert, \vert{n \cdot l}\vert + \vert{n \cdot v}\vert,α)} 4∣n⋅l∣∣n⋅v∣G(l,v)=lerp(2∣n⋅l∣∣n⋅v∣,∣n⋅l∣+∣n⋅v∣,α)0.5
2.4 各项异性几何函数总结
2.4.1 Unity HDRP方案
注意这里是算出来是 G ( l , v ) 4 ∣ n ⋅ l ∣ ∣ n ⋅ v ∣ \frac{G{}(l,v)}{4\vert{n \cdot l}\vert\vert n \cdot v\vert} 4∣n⋅l∣∣n⋅v∣G(l,v)
// Note: V = G / (4 * NdotL * NdotV)
// Ref: https://cedec.cesa.or.jp/2015/session/ENG/14698.html The Rendering Materials of Far Cry 4
float V_SmithJointGGXAniso(float TdotV, float BdotV, float NdotV, float TdotL, float BdotL, float NdotL, float roughnessT, float roughnessB, float partLambdaV)
{
float lambdaV = NdotL * length(real3(roughnessT * TdotV, roughnessB * BdotV, NdotV));
float lambdaL = NdotV * length(real3(roughnessT * TdotL, roughnessB * BdotL, NdotL));
return 0.5 / (lambdaV + lambdaL);
}