PBR
PBR是对物理的模拟,具有三点
- 基于微表面模型
- 能量守恒
- 使用基于物理的BRDF
我们介绍 Epic Games 采用的金属工作流。
微表面模型
所有的PBR技术都是基于微表面理论,该理论描述,在非常微观的尺度,物体表面是由很多小的完美的反射镜面构成,这些镜面称为微表面。
半向量在光线方向
l
l
l 和视线方向
v
v
v 的中间,为
h
=
l
+
v
∥
l
+
v
∥
h=\frac{l+v}{\|l+v\|}
h=∥l+v∥l+v
能量守恒
微表面理论必须满足能量守恒,即入射光能量必须大于等于出射光能量,其中出射光也包括散射的光。所以,在光滑的表面,反射光很强,但是范围很小;而粗糙的表面,反射光不强,但是范围很大。
- 折射和反射
当一束光打到一个表面上时,它分为折射(refraction)和反射(reflection)部分。反射部分则是直接在表面反射,没有进入表面,这杯称为高光(specular lighting)。而折射部分则进入表面被吸收,光子会在物体里继续向前移动与原子不断碰撞,随机移动,有些光子有机会再次从表面散射出来,这部分散射出来的光被称为漫反射(diffuse lighting)。这里我们假设所有的被吸收的折射光都只会在非常小的范围内碰撞,忽略在物体里跑了的距离很远的光子。而这部分跑了很远后,散射出来的光子在Shader的技术中被称为次表面散射(subsurface scattering),比如皮肤、大理石等,但是这个很耗,所以一般不考虑。 - 金属和半导体(绝缘体)
金属表面和非金属(绝缘体)表面对光照的表现截然不同,金属表面遵循相同的反射和折射原理,但是所有折射光都被直接吸收而没有散射。这意味着金属表面只有高光反射,没有漫反射,所以在PBR里面被单独对待了。
在能量守恒上,反射和折射是互斥的(mutually exclusive)。任何被材质反射的能量都不会再被材质吸收。
所以能量守恒可以如下计算出来
float kS = calculateSpecularComponent(...); // reflection/specular fraction
float kD = 1.0 - kS; // refraction/diffuse fraction
所以只要满足上面的条件,就一定不会导致出射光能量超过入射光。
反射公式
反射公式为
L
o
(
p
,
ω
o
)
=
∫
Ω
f
r
(
p
,
ω
i
,
ω
o
)
L
i
(
p
,
ω
i
)
n
⋅
ω
i
d
ω
i
L_o(p,\omega_o) = \int\limits_{\Omega} f_r(p,\omega_i,\omega_o) L_i(p,\omega_i) n \cdot \omega_i d\omega_i
Lo(p,ωo)=Ω∫fr(p,ωi,ωo)Li(p,ωi)n⋅ωidωi
- 其中 L o ( p , ω o ) L_o(p,\omega_o) Lo(p,ωo) 是 radiance,单位是 W ⋅ s r − 1 ⋅ m − 2 W⋅sr^{−1}⋅m^{−2} W⋅sr−1⋅m−2,描述的是在 p p p 点处,观察方向为 ω o \omega_o ωo 时的所有反射光 Irradiance 之和。
- f r ( p , ω i , ω o ) f_r(p,\omega_i,\omega_o) fr(p,ωi,ωo) 就是brdf,描述的是 reflected radiance 到 incident irradiance 之间的比例 f r ( p , ω i , ω o ) = d L o ( x , ω o ) d E i ( x , ω o ) f_r(p,\omega_i,\omega_o) = \frac{dL_o(x,\omega_o)}{dE_{i}(x,\omega_o)} fr(p,ωi,ωo)=dEi(x,ωo)dLo(x,ωo),其中 i r r a d i a n c e irradiance irradiance 的单位是 W ⋅ m − 2 W⋅m^{-2} W⋅m−2
- d ω i d\omega_i dωi 是球面度(solid angle)微分
辐射能量(Radiant energy)和辐射通量(Radiant flux)
辐射强度(Radiant intensity)
单位球面度上的辐射通量
Ω
=
∫
Ω
d
ω
=
∫
0
2
π
∫
0
π
sin
θ
d
θ
d
ϕ
=
4
π
\begin{aligned} \Omega &=\int_{\Omega} \mathrm{~d} \omega \\ &=\int_{0}^{2 \pi} \int_{0}^{\pi} \sin \theta \mathrm{d} \theta \mathrm{d} \phi \\ &=4 \pi \end{aligned}
Ω=∫Ω dω=∫02π∫0πsinθdθdϕ=4π
辐照度(Irradiance)
可以理解为单位面积上朝着当前面法线方向的辐射通量
辐射率(radiance)
可以理解为单位面积上单位球面度上朝着特定方向的辐射通量
L
(
p
,
ω
)
=
d
E
(
p
)
d
ω
cos
θ
L(\mathrm{p}, \omega)=\frac{\mathrm{d} E(\mathrm{p})}{\mathrm{d} \omega \cos \theta}
L(p,ω)=dωcosθdE(p)
BRDF
brdf就是基于微表面理论模拟材质的反射和折射性质的函数。
我们介绍的BRDF是
渲染方程只是在反射方程上加上了自发光,其实光线折射入物体表面后,再次通过漫反射发射出来的时候可以理解为物体的自发光。
更进一步可以看https://zhuanlan.zhihu.com/p/145410416
Cook-Torrance BRDF包含 diffuse 和 specular 两部分
f
r
=
k
d
f
l
a
m
b
e
r
t
+
k
s
f
c
o
o
k
−
t
o
r
r
a
n
c
e
f_r = k_d f_{lambert} + k_s f_{cook-torrance}
fr=kdflambert+ksfcook−torrance
其中
k
d
k_d
kd 就是前面提到的折射部分能量比例,
k
s
k_s
ks 则是反射部分能量比例。折射部分的式子表示的 lambert 表面上的漫反射式子
f
l
a
m
b
e
r
t
=
c
π
f_{lambert} = \frac{c}{\pi}
flambert=πc
关于 Lambert表面系数的推导可以看 Lambert表面的brdf推导 这篇博客。
反射部分式子则是
f
C
o
o
k
T
o
r
r
a
n
c
e
=
D
F
G
4
(
ω
o
⋅
n
)
(
ω
i
⋅
n
)
f_{CookTorrance} = \frac{DFG}{4(\omega_o \cdot n)(\omega_i \cdot n)}
fCookTorrance=4(ωo⋅n)(ωi⋅n)DFG
由三个部分组成
- 法线分布函数(Normal distribution function):逼近朝向半向量方向的为表面的微表面的分布情况,受表面 roughness参数影响。这是逼近微表面的基础函数。
- 几何分布函数(Geometry function):描述微表面的的自遮挡和自阴影。表面粗糙度越大,微表面由于自遮挡和自阴影能够反射的光就越少。
- 菲涅尔公式(Fresnel equation):菲尼尔公式则是描述表面不同角度下的表面反射系数,是一个通用的物理性质。
接下来我们将要讲 Unreal的
- Trowbridge-Reitz GGX 的 D D D
- Fresnel-Schlick 的 F F F
- 以及 Smith’s Schlick-GGX 的 G G G
法线分布函数(Normal distribution function)
Trowbridge-Reitz GGX 的
D
D
D
N
D
F
G
G
X
T
R
(
n
,
h
,
α
)
=
α
2
π
(
(
n
⋅
h
)
2
(
α
2
−
1
)
+
1
)
2
NDF_{GGX TR}(n, h, \alpha) = \frac{\alpha^2}{\pi((n \cdot h)^2 (\alpha^2 - 1) + 1)^2}
NDFGGXTR(n,h,α)=π((n⋅h)2(α2−1)+1)2α2
其中
h
h
h 是半向量方向,我们前面定义过了。
α
\alpha
α 是表面粗糙度。粗糙度越大,微表面方向越是散乱,
D
D
D 就越小。
用GLSL写出来是
float DistributionGGX(vec3 N, vec3 H, float a)
{
float a2 = a*a;
float NdotH = max(dot(N, H), 0.0);
float NdotH2 = NdotH*NdotH;
float nom = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;
return nom / denom;
}
几何分布函数(Geometry function)
几何分布函数逼近的是统计上微表面对其他表面的遮蔽的逼近
几何分布函数使用的是GGX和Schlick-Beckmann approximation的组合,被称为 Schlick-GGX
G
S
c
h
l
i
c
k
G
G
X
(
n
,
v
,
k
)
=
n
⋅
v
(
n
⋅
v
)
(
1
−
k
)
+
k
G_{SchlickGGX}(n, v, k) = \frac{n \cdot v} {(n \cdot v)(1 - k) + k }
GSchlickGGX(n,v,k)=(n⋅v)(1−k)+kn⋅v
这里
k
k
k 是粗糙度
α
\alpha
α 的映射,当使用几何分布函数计算直接光和IBL光照的时候,分别是
k
d
i
r
e
c
t
=
(
α
+
1
)
2
8
k_{direct} = \frac{(\alpha + 1)^2}{8}
kdirect=8(α+1)2
k
I
B
L
=
α
2
2
k_{IBL} = \frac{\alpha^2}{2}
kIBL=2α2
为了更好的逼近几何情形,我们可以同时考虑视线方向(几何遮蔽)以及光线方向(几何阴影)
G
(
n
,
v
,
l
,
k
)
=
G
s
u
b
(
n
,
v
,
k
)
G
s
u
b
(
n
,
l
,
k
)
G(n, v, l, k) = G_{sub}(n, v, k) G_{sub}(n, l, k)
G(n,v,l,k)=Gsub(n,v,k)Gsub(n,l,k)
用GLSL出来就是
float GeometrySchlickGGX(float NdotV, float k)
{
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
float GeometrySmith(vec3 N, vec3 V, vec3 L, float k)
{
float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
float ggx1 = GeometrySchlickGGX(NdotV, k);
float ggx2 = GeometrySchlickGGX(NdotL, k);
return ggx1 * ggx2;
}
菲涅尔函数(Fresnel equation)
菲涅尔函数描述的是反射与折射的比值,这跟观察角度相关,随着观察角变大,菲涅尔反射率也越大。
F
S
c
h
l
i
c
k
(
h
,
v
,
F
0
)
=
F
0
+
(
1
−
F
0
)
(
1
−
(
h
⋅
v
)
)
5
F_{Schlick}(h, v, F_0) = F_0 + (1 - F_0) ( 1 - (h \cdot v))^5
FSchlick(h,v,F0)=F0+(1−F0)(1−(h⋅v))5
而每个材质表面都有基础反射率
F
o
F_o
Fo,我们用折射率(IOR)来表示。当我们从表面法线反方向看向表面的时候,得到的反射率就是 normal incidence (
F
0
F_0
F0)。
有几个需要注意的点。Fresnel-Schlick approximation 只定义在绝缘体即非金属表面。对于导体表面,这个逼近不成立。而我们可以通过金属度(metalness)来差值得到近似的
F
0
F_0
F0,从而对金属表面也使用相同的式子。
常见表面的 IOR 表如下
通过观察,我们可以看到,所有的绝缘体的 base IOR 都没有超过 0.17。然而道题的 base IOR 则非常高,都在0.5到1.0之间变化,而且导体的三个通道的 base IOR 都不一样。
金属的特殊属性导致被称为金属工作流,我们可以通过金属度参数(metalness)来描述一个表面是不是金属表面。最主要是可以对金属和非金属表面使用相同的函数形式了。
vec3 F0 = vec3(0.04);
F0 = mix(F0, surfaceColor.rgb, metalness);
我们对非金属使用的是平均 F 0 F_0 F0 是 0.01,因为金属表面吸收了所有的折射光,所以我们没有漫反射,则我们可以直接使用表面的颜色
vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
其中 cosTheta 是发现表面向量 n n n 与半向量 h h h 的点积。
Cook-Torrance reflectance equation
最终的BRDF的形式为
L
o
(
p
,
ω
o
)
=
∫
Ω
(
k
d
c
π
+
k
s
D
F
G
4
(
ω
o
⋅
n
)
(
ω
i
⋅
n
)
)
L
i
(
p
,
ω
i
)
n
⋅
ω
i
d
ω
i
L_o(p,\omega_o) = \int\limits_{\Omega} (k_d\frac{c}{\pi} + k_s\frac{DFG}{4(\omega_o \cdot n)(\omega_i \cdot n)}) L_i(p,\omega_i) n \cdot \omega_i d\omega_i
Lo(p,ωo)=Ω∫(kdπc+ks4(ωo⋅n)(ωi⋅n)DFG)Li(p,ωi)n⋅ωidωi
因为
k
s
k_s
ks 表示的是BRDF的反射系数,而菲涅尔系数表示的也是光线在表面的反射情况,所以specular BRDF隐式的包含了反射部分系数
k
s
k_s
ks,则我们最终的形式变成
L
o
(
p
,
ω
o
)
=
∫
Ω
(
k
d
c
π
+
D
F
G
4
(
ω
o
⋅
n
)
(
ω
i
⋅
n
)
)
L
i
(
p
,
ω
i
)
n
⋅
ω
i
d
ω
i
L_o(p,\omega_o) = \int\limits_{\Omega} (k_d\frac{c}{\pi} + \frac{DFG}{4(\omega_o \cdot n)(\omega_i \cdot n)}) L_i(p,\omega_i) n \cdot \omega_i d\omega_i
Lo(p,ωo)=Ω∫(kdπc+4(ωo⋅n)(ωi⋅n)DFG)Li(p,ωi)n⋅ωidωi
最终使用我写的软渲染器,得到
从左往右是金属度(Metallic)从0到1
上下往上是粗糙度(Roughness)从0到1
左边有个光源
NDF是怎么定义的
the NDF is not a probability density at all! Rather, it’s the density of micro-area over the joint domain of macro-area and solid angle. The area units cancel, so the NDF still has units of inverse solid angle
NDF不是概率密度。它是宏表面和方位角联合条件下的微表面密度分布。
根据Microfacet Models for Refraction through Rough Surfaces,NDF满足
d
A
h
=
D
(
h
)
d
ω
h
A
dA_{h}=D(h)d\omega_{h}A
dAh=D(h)dωhA
其中
A
A
A 是微平面的微分量,即一个比微平面大的小块,
d
A
h
dA_{h}
dAh 则是在发现方向为
n
n
n的微平面
A
A
A中,方位角位于
d
ω
h
d \omega_{h}
dωh的全部区域。
标准化的形式为
1
A
∫
(
n
⋅
h
)
d
A
h
=
∫
Ω
D
(
h
)
(
n
⋅
h
)
d
ω
h
\frac{1}{A}\int (n \cdot h) d A_{h} = \int_{\Omega} D(h) (n \cdot h) d \omega_{h}
A1∫(n⋅h)dAh=∫ΩD(h)(n⋅h)dωh
等式左边是对在一个小块中,对所有的微表面的面积的积分;而右边是在半球面上朝着方位角的 NDF 的积分。
而Microfacet Models for Refraction through Rough Surfaces中给出了更强的条件。对于任何方向
v
v
v,我们的NDF都应该满足
∫
Ω
D
(
h
)
(
v
⋅
h
)
d
ω
h
=
n
⋅
v
\int_{\Omega}D(h)(v \cdot h) d\omega_{h} = n \cdot v
∫ΩD(h)(v⋅h)dωh=n⋅v
前面的标准化在这里也只是特殊的
v
=
n
v=n
v=n。这个更强的限制保证了流形(manifold)下NDF的一致性,而前面的形式只对以三角形为基础的模型有效。
所以我们在推导特定的NDF的时候,必须要注意它的计算形式。
常用的BRDF分量 http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
GGX重要性采样推导
N D F G G X ( n , h , α ) = α 2 π ( c o s θ 2 ( α 2 − 1 ) + 1 ) 2 \large{NDF_{GGX}(n,h,\alpha)=\frac{{\alpha}^2}{\pi {( {cos\theta}^2 ({\alpha}^2 - 1) + 1)}^2}} NDFGGX(n,h,α)=π(cosθ2(α2−1)+1)2α2
因为 ∫ D ( m ) c o s ( θ m ) d ω = 1 \int D(m)cos(\theta_m)d\omega=1 ∫D(m)cos(θm)dω=1
而微观下,立体角对应的曲面可以当做小矩形,则其微分 d ω = d A = sin θ d θ d ϕ d\omega=dA=\sin\theta d\theta d\phi dω=dA=sinθdθdϕ
所以
∫
D
(
h
)
cos
θ
sin
θ
d
θ
d
ϕ
=
1
\int D(h)\cos{\theta}\sin{\theta}d{\theta}d{\phi}=1
∫D(h)cosθsinθdθdϕ=1
把GGX带入进去,可以得到
p
(
θ
,
ϕ
)
=
α
2
c
o
s
θ
s
i
n
θ
π
(
c
o
s
θ
2
(
α
2
−
1
)
+
1
)
2
\large{p(\theta,\phi)=\frac{{\alpha}^2 cos\theta sin\theta}{\pi {( {cos\theta}^2 ({\alpha}^2 - 1) + 1)}^2}}
p(θ,ϕ)=π(cosθ2(α2−1)+1)2α2cosθsinθ
求
θ
\theta
θ 和
ϕ
\phi
ϕ 的边缘概率密度函数,得:
p
h
(
θ
)
=
∫
0
2
π
p
h
(
θ
,
ϕ
)
d
ϕ
=
2
α
2
cos
θ
sin
θ
(
(
α
2
−
1
)
cos
2
θ
+
1
)
2
p_{h}(\theta)=\int_{0}^{2 \pi} p_{h}(\theta, \phi) d \phi=\frac{2 \alpha^{2} \cos \theta \sin \theta}{\left(\left(\alpha^{2}-1\right) \cos ^{2} \theta+1\right)^{2}}
ph(θ)=∫02πph(θ,ϕ)dϕ=((α2−1)cos2θ+1)22α2cosθsinθ
和
p
h
(
ϕ
)
=
∫
0
π
2
p
h
(
θ
,
ϕ
)
d
θ
=
∫
0
π
2
α
2
cos
θ
sin
θ
π
(
(
α
2
−
1
)
cos
2
θ
+
1
)
2
d
θ
=
α
2
2
π
∫
π
2
0
d
(
cos
2
θ
)
(
(
α
2
−
1
)
cos
2
θ
+
1
)
2
=
α
2
2
π
∫
0
1
d
t
(
(
α
2
−
1
)
t
+
1
)
2
=
α
2
2
π
(
α
2
−
1
)
∫
1
α
2
d
x
x
2
=
α
2
2
π
(
α
2
−
1
)
⋅
1
x
∣
α
2
1
=
1
2
π
\begin{aligned} p_{h}(\phi) &=\int_{0}^{\frac{\pi}{2}} p_{h}(\theta, \phi) d \theta=\int_{0}^{\frac{\pi}{2}} \frac{\alpha^{2} \cos \theta \sin \theta}{\pi\left(\left(\alpha^{2}-1\right) \cos ^{2} \theta+1\right)^{2}} d \theta \\ &=\frac{\alpha^{2}}{2 \pi} \int_{\frac{\pi}{2}}^{0} \frac{d\left(\cos ^{2} \theta\right)}{\left(\left(\alpha^{2}-1\right) \cos ^{2} \theta+1\right)^{2}} \\ &=\frac{\alpha^{2}}{2 \pi} \int_{0}^{1} \frac{d t}{\left(\left(\alpha^{2}-1\right) t+1\right)^{2}} \\ &=\frac{\alpha^{2}}{2 \pi\left(\alpha^{2}-1\right)} \int_{1}^{\alpha^{2}} \frac{d x}{x^{2}} \\ &=\left.\frac{\alpha^{2}}{2 \pi\left(\alpha^{2}-1\right)} \cdot \frac{1}{x}\right|_{\alpha^{2}} ^{1} \\ &=\frac{1}{2 \pi} \end{aligned}
ph(ϕ)=∫02πph(θ,ϕ)dθ=∫02ππ((α2−1)cos2θ+1)2α2cosθsinθdθ=2πα2∫2π0((α2−1)cos2θ+1)2d(cos2θ)=2πα2∫01((α2−1)t+1)2dt=2π(α2−1)α2∫1α2x2dx=2π(α2−1)α2⋅x1∣∣∣∣α21=2π1
进一步求得
θ
\theta
θ 和
ϕ
\phi
ϕ 的CDF:
P
h
(
ϕ
)
=
ϕ
2
π
P_h(\phi)=\frac{\phi}{2\pi}
Ph(ϕ)=2πϕ
和
P
h
(
θ
)
=
∫
0
θ
2
α
2
costsin
t
(
(
α
2
−
1
)
cos
2
t
+
1
)
2
d
t
=
α
2
∫
θ
0
d
(
cos
2
t
)
(
(
α
2
−
1
)
cos
2
t
+
1
)
2
=
α
2
α
2
−
1
∫
(
α
2
−
1
)
cos
2
θ
+
1
α
2
d
x
x
2
=
α
2
α
2
−
1
⋅
1
x
∣
α
2
(
α
2
−
1
)
cos
2
θ
+
1
=
α
2
(
α
2
−
1
)
2
cos
2
θ
+
(
α
2
−
1
)
−
1
α
2
−
1
\begin{aligned} P_{h}(\theta) &=\int_{0}^{\theta} \frac{2 \alpha^{2} \operatorname{costsin} t}{\left(\left(\alpha^{2}-1\right) \cos ^{2} t+1\right)^{2}} d t \\ &=\alpha^{2} \int_{\theta}^{0} \frac{d\left(\cos ^{2} t\right)}{\left(\left(\alpha^{2}-1\right) \cos ^{2} t+1\right)^{2}} \\ &=\frac{\alpha^{2}}{\alpha^{2}-1} \int_{\left(\alpha^{2}-1\right) \cos ^{2} \theta+1}^{\alpha^{2}} \frac{d x}{x^{2}} \\ &=\left.\frac{\alpha^{2}}{\alpha^{2}-1} \cdot \frac{1}{x}\right|_{\alpha^{2}} ^{\left(\alpha^{2}-1\right) \cos ^{2} \theta+1} \\ &=\frac{\alpha^{2}}{\left(\alpha^{2}-1\right)^{2} \cos ^{2} \theta+\left(\alpha^{2}-1\right)}-\frac{1}{\alpha^{2}-1} \end{aligned}
Ph(θ)=∫0θ((α2−1)cos2t+1)22α2costsintdt=α2∫θ0((α2−1)cos2t+1)2d(cos2t)=α2−1α2∫(α2−1)cos2θ+1α2x2dx=α2−1α2⋅x1∣∣∣∣α2(α2−1)cos2θ+1=(α2−1)2cos2θ+(α2−1)α2−α2−11
设两个[0,1]之间的随机数
ξ
\xi
ξ 和
ϵ
\epsilon
ϵ 分别对应
P
h
(
ϕ
)
P_h(\phi)
Ph(ϕ) 和
P
h
(
θ
)
P_h(\theta)
Ph(θ),使用Inverse transform可以计算得到
ϕ
=
2
π
ξ
θ
=
a
r
c
c
o
s
1
−
ϵ
ϵ
(
α
2
−
1
)
+
1
\phi = 2\pi\xi\\ \theta = arccos\sqrt{\frac{1-\epsilon}{\epsilon(\alpha^2 - 1) + 1}}
ϕ=2πξθ=arccosϵ(α2−1)+11−ϵ
我们在做IBL的SplitSum的计算的时候,对GGX做重要性采样,就需要使用到以上的推导,对每个不同的 roughness 做以GGX为分布的采样。得到不同roughness对应的irradiance map。
IBL
IBL本质是将周围的环境作为一个复杂的光源,跟直接光照不一样。
实际操作就是在当前点获取周围环境的cubemap,并把这个cubemap拿来做IBL的预计算。
根据光照等式
L
o
(
p
,
ω
o
)
=
∫
Ω
(
k
d
c
π
+
D
F
G
4
(
ω
o
⋅
n
)
(
ω
i
⋅
n
)
)
L
i
(
p
,
ω
i
)
n
⋅
ω
i
d
ω
i
=
∫
Ω
(
k
d
c
π
)
L
i
(
p
,
ω
i
)
n
⋅
ω
i
d
ω
i
+
∫
Ω
(
D
F
G
4
(
ω
o
⋅
n
)
(
ω
i
⋅
n
)
)
L
i
(
p
,
ω
i
)
n
⋅
ω
i
d
ω
i
\begin{aligned} L_o(p,\omega_o) &= \int\limits_{\Omega} (k_d\frac{c}{\pi} + \frac{DFG}{4(\omega_o \cdot n)(\omega_i \cdot n)}) L_i(p,\omega_i) n \cdot \omega_i d\omega_i \\ &= \int\limits_{\Omega} (k_d\frac{c}{\pi}) L_i(p,\omega_i) n \cdot \omega_i d\omega_i + \int\limits_{\Omega} (\frac{DFG}{4(\omega_o \cdot n)(\omega_i \cdot n)}) L_i(p,\omega_i) n \cdot \omega_i d\omega_i \\ \end{aligned}
Lo(p,ωo)=Ω∫(kdπc+4(ωo⋅n)(ωi⋅n)DFG)Li(p,ωi)n⋅ωidωi=Ω∫(kdπc)Li(p,ωi)n⋅ωidωi+Ω∫(4(ωo⋅n)(ωi⋅n)DFG)Li(p,ωi)n⋅ωidωi
对于左边的 diffuse 部分,积分中的变量只跟面法向量
n
n
n 、入射光方向
ω
i
\omega_i
ωi 以及面上点位置
p
p
p 有关。因为这是预计算的过程,所以可以直接对整个半球面都积分都可以,而不需要采样的积分,关于采样的积分可以看球谐光分析中的采样空间光照信息的时候使用的蒙特卡洛采样方法
一般期望的计算
∫
−
∞
∞
f
(
x
)
d
x
=
∫
−
∞
∞
f
(
x
)
p
(
x
)
p
(
x
)
d
x
=
E
(
f
(
x
)
p
(
x
)
)
其中
p
(
x
)
是随机变量取
f
(
x
)
p
(
x
)
的概率
⇓
根据大数定理,样本均值依概率收敛于期望值
⇓
E
(
g
(
x
)
)
≈
1
N
∑
i
=
1
N
g
(
x
i
)
\begin{aligned} \int_{-\infty}^{\infty} f(x)dx &= \int_{-\infty}^{\infty} \frac{f(x)}{p(x)}p(x)dx\\ &= E(\frac{f(x)}{p(x)}) \quad \text{ 其中 } p(x) \text{ 是随机变量取 } \frac{f(x)}{p(x)} \text{ 的概率}\\ \end{aligned} \\ \Downarrow \\ \text{根据大数定理,样本均值依概率收敛于期望值}\\ \Downarrow \\ E(g(x)) \approx \frac{1}{N} \sum_{i=1}^{N} g(x_i)
∫−∞∞f(x)dx=∫−∞∞p(x)f(x)p(x)dx=E(p(x)f(x)) 其中 p(x) 是随机变量取 p(x)f(x) 的概率⇓根据大数定理,样本均值依概率收敛于期望值⇓E(g(x))≈N1i=1∑Ng(xi)
漫反射部分的IBL积分
所以最后对 brdf 左边的 diffuse 做的积分,把折射率
k
d
k_d
kd 和 表面颜色
c
c
c 拿出来,得到
L
d
i
f
f
u
s
e
(
p
,
ω
o
)
=
k
d
c
π
∫
Ω
L
i
(
p
,
ω
i
)
n
⋅
ω
i
d
ω
i
=
k
d
c
π
∫
ϕ
=
0
2
π
∫
θ
=
0
π
/
2
L
i
(
p
,
ω
i
)
cos
(
θ
)
sin
(
θ
)
d
θ
d
ϕ
=
k
d
c
π
2
π
n
1
π
/
2
n
2
∑
n
ϕ
=
0
n
1
∑
n
θ
=
0
n
2
L
i
(
p
,
ϕ
i
,
θ
i
)
cos
(
θ
)
sin
(
θ
)
\begin{aligned} L_{diffuse}(p,\omega_o) &= k_{d} \frac{c}{\pi} \int\limits_{\Omega} L_i(p,\omega_i) n \cdot \omega_i d\omega_i\\ &= k_{d} \frac{c}{\pi} \int_{\phi=0}^{2\pi}\int_{\theta=0}^{\pi/2} L_i(p, \omega_{i}) \cos(\theta) \sin(\theta) d \theta d\phi\\ &= k_{d} \frac{c}{\pi}\frac{2\pi}{n_{1}}\frac{\pi/2}{n_{2}} \sum_{n_{\phi} = 0}^{n1} \sum_{n_{\theta} = 0}^{n2} L_i(p,\phi_i, \theta_i) \cos(\theta) \sin(\theta) \end{aligned}
Ldiffuse(p,ωo)=kdπcΩ∫Li(p,ωi)n⋅ωidωi=kdπc∫ϕ=02π∫θ=0π/2Li(p,ωi)cos(θ)sin(θ)dθdϕ=kdπcn12πn2π/2nϕ=0∑n1nθ=0∑n2Li(p,ϕi,θi)cos(θ)sin(θ)
这里的积分只依赖于
ω
i
\omega_{i}
ωi ,我们通过预计算,在新的cubemap的每个像素位,即每个采样方向
ω
o
\omega_{o}
ωo 上存上 diffuse 的卷积结果。
积分的代码如下所示
vec3 irradiance = vec3(0.0);
vec3 up = vec3(0.0, 1.0, 0.0);
vec3 right = cross(up, normal);
up = cross(normal, right);
float sampleDelta = 0.025;
float nrSamples = 0.0;
for(float phi = 0.0; phi < 2.0 * PI; phi += sampleDelta)
{
for(float theta = 0.0; theta < 0.5 * PI; theta += sampleDelta)
{
// spherical to cartesian (in tangent space)
vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
// tangent space to world
vec3 sampleVec = tangentSample.x * right + tangentSample.y * up + tangentSample.z * N;
irradiance += texture(environmentMap, sampleVec).rgb * cos(theta) * sin(theta);
nrSamples++;
}
}
irradiance = PI * irradiance * (1.0 / float(nrSamples));
最后积分的结果是 Irradiance Map,存在一个cubemap中,在使用的时候,直接根据相机方向的反方向采样这个cubemap,得到的结果乘以 c c c 作为diffuse 部分的光照输入。
vec3 ambient = texture(irradianceMap, N).rgb;
vec3 kS = fresnelSchlick(max(dot(N, V), 0.0), F0);
vec3 kD = 1.0 - kS;
vec3 irradiance = texture(irradianceMap, N).rgb;
vec3 diffuse = irradiance * albedo;
vec3 ambient = (kD * diffuse) * ao;
因为diffuse是由平面顶点法线方向的半球积分得来的,所以计算菲涅尔时使用的是顶点法线与视线反方向的夹角。
高光反射部分的IBL积分
光照积分式子的右边部分则可以用[6]中说的 Split Sum Approximation。
根据大数定理
L
c
o
o
k
−
t
o
r
r
a
n
c
e
(
p
,
ω
o
)
=
∫
Ω
(
D
F
G
4
(
ω
o
⋅
n
)
(
ω
i
⋅
n
)
L
i
(
p
,
ω
i
)
n
⋅
ω
i
d
ω
i
=
∫
Ω
f
r
(
p
,
ω
i
,
ω
o
)
L
i
(
p
,
ω
i
)
n
⋅
ω
i
d
ω
i
≈
1
N
∑
k
=
1
N
L
i
(
ω
k
)
f
r
(
ω
k
,
ω
o
)
cos
θ
ω
k
p
(
ω
k
,
ω
o
)
≈
(
1
N
∑
k
=
1
N
L
i
(
ω
k
)
)
(
1
N
∑
k
=
1
N
f
r
(
ω
k
,
ω
o
)
cos
θ
ω
k
p
(
ω
k
,
ω
o
)
)
\begin{aligned} L_{cook-torrance}(p,\omega_o) &= \int\limits_{\Omega} (\frac{DFG}{4(\omega_o \cdot n)(\omega_i \cdot n)} L_i(p,\omega_i) n \cdot \omega_i d\omega_i \\ &= \int\limits_{\Omega} f_r(p, \omega_i, \omega_o) L_i(p,\omega_i) n \cdot \omega_i d\omega_i\\ &\approx \frac{1}{N} \sum_{k=1}^{N} \frac{L_{i}(\omega_{k})f_{r}(\omega_k, \omega_o)\cos{\theta_{\omega_{k}}}}{p(\omega_k, \omega_o)}\\ &\approx \left (\frac{1}{N} \sum_{k=1}^{N}L_{i}(\omega_{k})\right )\left ( \frac{1}{N} \sum_{k=1}^{N} \frac{f_{r}(\omega_k, \omega_o)\cos{\theta_{\omega_{k}}}}{p(\omega_k, \omega_o)} \right ) \end{aligned}
Lcook−torrance(p,ωo)=Ω∫(4(ωo⋅n)(ωi⋅n)DFGLi(p,ωi)n⋅ωidωi=Ω∫fr(p,ωi,ωo)Li(p,ωi)n⋅ωidωi≈N1k=1∑Np(ωk,ωo)Li(ωk)fr(ωk,ωo)cosθωk≈(N1k=1∑NLi(ωk))(N1k=1∑Np(ωk,ωo)fr(ωk,ωo)cosθωk)
Pre-Filtered Environment Map
预计算高光反射的左边部分的积分。对于不同的 roughness 值,结果被存到cubemap不同的mip-map等级中。这里我们使用我们使用重要性采样对GGX分布与环境cubemap进行卷积。这里我们假设 n = v = r n=v=r n=v=r。这个各向同性的假设使得我们在与表面倾角很大的时候没法获得长的反射,这也是IBL中的一个大的误差来源。
float3 ImportanceSampleGGX( float2 Xi, float Roughness , float3 N )
{
float a = Roughness * Roughness;
float Phi = 2 * PI * Xi.x;
float CosTheta = sqrt( (1 - Xi.y) / ( 1 + (a*a - 1) * Xi.y ) );
float SinTheta = sqrt( 1 - CosTheta * CosTheta );
float3 H;
H.x = SinTheta * cos( Phi );
H.y = SinTheta * sin( Phi );
H.z = CosTheta;
float3 UpVector = abs(N.z) < 0.999 ? float3(0,0,1) : float3(1,0,0);
float3 TangentX = normalize( cross( UpVector , N ) );
float3 TangentY = cross( N, TangentX );
// Tangent to world space
return TangentX * H.x + TangentY * H.y + N * H.z;
}
float3 PrefilterEnvMap( float Roughness , float3 R )
{
float3 N = R;
float3 V = R;
float3 PrefilteredColor = 0;
const uint NumSamples = 1024;
for( uint i = 0; i < NumSamples; i++ )
{
float2 Xi = Hammersley( i, NumSamples );
float3 H = ImportanceSampleGGX( Xi, Roughness , N );
float3 L = 2 * dot( V, H ) * H - V;
float NoL = saturate( dot( N, L ) );
if( NoL > 0 )
{
PrefilteredColor += EnvMap.SampleLevel( EnvMapSampler , L, 0 ).rgb * NoL;
TotalWeight += NoL;
}
}
return PrefilteredColor / TotalWeight;
}
Environment BRDF
第二部分则包含其他剩下的积分部分。这跟把BRDF与纯白的环境积分一样。通过把
F
(
v
,
h
)
=
F
0
+
(
1
−
F
0
)
(
1
−
v
⋅
h
)
5
F(v,h)=F_{0}+(1-F_{0})(1-v \cdot h)^{5}
F(v,h)=F0+(1−F0)(1−v⋅h)5
置换进去,我们可以把
F
0
F_{0}
F0 从积分中分离开
∫
H
f
(
l
,
v
)
cos
θ
l
d
l
=
F
0
∫
H
f
(
l
.
v
)
F
(
v
,
h
)
(
1
−
(
1
−
v
⋅
h
)
5
)
cos
θ
l
d
l
+
∫
H
f
(
l
,
v
)
F
(
v
,
h
)
(
1
−
v
⋅
h
)
5
cos
θ
l
d
l
\int\limits_{H} f(l,v)\cos\theta_{l}dl=F_{0}\int\limits_{H} \frac{f(l.v)}{F(v,h)}(1-(1-v \cdot h)^{5})\cos{\theta_{l}}dl + \int\limits_{H} \frac{f(l,v)}{F(v,h)}(1-v\cdot h)^{5}\cos\theta_{l}dl
H∫f(l,v)cosθldl=F0H∫F(v,h)f(l.v)(1−(1−v⋅h)5)cosθldl+H∫F(v,h)f(l,v)(1−v⋅h)5cosθldl
这导致有两个输入( Roughness 和
cos
θ
v
\cos\theta_{v}
cosθv )和两个输出 (一个放大系数和一个
F
0
的
偏
移
F_{0}的偏移
F0的偏移)。我们可以把结果计算并预存到一个 2DLUT上。
float2 IntegrateBRDF( float Roughness, float NoV )
{
float3 V;
V.x = sqrt( 1.0f - NoV * NoV ); // sin
V.y = 0;
V.z = NoV; // cos
float A = 0;
float B = 0;
const uint NumSamples = 1024;
for( uint i = 0; i < NumSamples; i++ )
{
float2 Xi = Hammersley( i, NumSamples );
float3 H = ImportanceSampleGGX( Xi, Roughness , N );
float3 L = 2 * dot( V, H ) * H - V;
float NoL = saturate( L.z );
float NoH = saturate( H.z );
float VoH = saturate( dot( V, H ) );
if( NoL > 0 )
{
float G = G_Smith( Roughness , NoV, NoL );
float G_Vis = G * VoH / (NoH * NoV);
float Fc = pow( 1 - VoH, 5 );
A += (1 - Fc) * G_Vis;
B += Fc * G_Vis;
}
}
return float2( A, B ) / NumSamples;
}
逼近通过重要性采样得到结果
float3 ApproximateSpecularIBL( float3 SpecularColor, float Roughness, float3 N, float3 V )
{
float NoV = saturate( dot( N, V ) );
float3 R = 2 * dot( V, N ) * N - V;
float3 PrefilteredColor = PrefilterEnvMap( Roughness , R );
float2 EnvBRDF = IntegrateBRDF( Roughness , NoV );
return PrefilteredColor * ( SpecularColor * EnvBRDF.x + EnvBRDF.y );
}
引用
[1]https://learnopengl.com/PBR/Theory
[2]https://en.wikipedia.org/wiki/Radiance
[3]http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
[4]http://www.reedbeta.com/blog/hows-the-ndf-really-defined/
[5]http://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.html
[6]https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
[7]https://www.trentreed.net/blog/physically-based-shading-and-image-based-lighting/
[8]https://chetanjags.wordpress.com/2015/08/26/image-based-lighting/