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);
}