【实时渲染】《Real Time Rendering 4th》9.3 章读书笔记
在着色模型中,我们通常以下两个表示从位置 x 出射或者入射的光的光亮度。
L
o
(
x
,
d
)
或
者
L
i
(
x
,
d
)
L_o(\textbf{x}, \textbf{d}) 或者 L_i(\textbf{x}, \textbf{d})
Lo(x,d)或者Li(x,d)
- x:光的出射或者入射点
- d:光的方向
渲染的最终目的就是计算到达相机上的每一个点的光亮度,即来自方向 v 的射进处于位置 c 的相机的光亮度。
L
i
(
c
,
−
v
)
L_i(\textbf{c}, -\textbf{v})
Li(c,−v)
这个值在不考虑参与介质的情况下,约等于从最近的物体上出射的来自方向 v 的光线的亮度:
L
i
(
c
,
−
v
)
=
L
o
(
p
,
−
v
)
L_i(\textbf{c}, -\textbf{v}) = L_o(\textbf{p}, -\textbf{v})
Li(c,−v)=Lo(p,−v)
其中 p 是光线在某一个物体上出射的点。
来自 p 的光线有时候是物体自身的发光,也可能是光线照射到物体表面反射的光,也可能是来自其他物体反射的光之后二次反射的光,但我们这里只考虑直接反射的光,还有局部的此表面反射现象。
现在还需要解决一个问题,就是我们还需要衡量照射到物体表面的光经过反射之后,在特定方向上能够反射多少光。这可以用一个函数去描述反射光在空间当中的分布,这就是 BRDF,双向反射分布函数,记为
f
(
l
,
v
)
f(\textbf{l}, \textbf{v})
f(l,v)
- l 是光的输入方向
- v 本来是观察者方向
将 l 和 任意方向的 v 输入方程,BRDF将输出来自方向 l 的光在方向 v 的反射率。
l 和 v 都有两个*度,可以用方位角衡量:
现在知道物体表面的BRDF之后,就可以写出光照强度的表达式,在某一个方位上的入射到物体的光与BRDF的乘积,根据入射角进行修正之后得到在方向 v 上反射强度,然后对入射光进行积分,就得到所有入射到物体 p 点的光在方向 v 的反射强度。
L
o
(
p
,
−
v
)
=
∫
l
∈
Ω
f
(
l
,
v
)
L
i
(
p
,
l
)
(
n
⋅
l
)
d
l
(9.4)
L_o(\textbf{p}, -\textbf{v}) = \int_{l\in \Omega}f(\textbf{l}, \textbf{v})L_i(\textbf{p},\textbf{l})(\textbf{n}\cdot \textbf{l})d\textbf{l}\tag{9.4}
Lo(p,−v)=∫l∈Ωf(l,v)Li(p,l)(n⋅l)dl(9.4)
为了简便,我们把公式中的 p 省略掉,然后将代表每个向量的方位角带入上式得到:
L
o
(
θ
o
,
ϕ
o
)
=
∫
ϕ
i
=
0
2
π
∫
θ
i
=
0
π
/
2
f
(
θ
i
,
ϕ
i
,
θ
o
,
ϕ
o
)
L
i
(
θ
i
,
ϕ
i
)
c
o
s
θ
i
s
i
n
θ
i
d
θ
i
d
ϕ
i
(9.5)
L_o(\theta_o,\phi_o) = \int^{2\pi}_{\phi_i=0}\int^{\pi/2}_{\theta_i=0}f(\theta_i,\phi_i,\theta_o,\phi_o)L_i(\theta_i,\phi_i)cos\theta_i sin\theta_i d\theta_i d\phi_i\tag{9.5}
Lo(θo,ϕo)=∫ϕi=02π∫θi=0π/2f(θi,ϕi,θo,ϕo)Li(θi,ϕi)cosθisinθidθidϕi(9.5)
我们还可以变换参数,将三角函数消除掉,令:
μ
i
=
c
o
s
θ
i
μ
o
=
c
o
s
θ
o
\mu_i=cos\theta_i\\\mu_o=cos\theta_o
μi=cosθiμo=cosθo
代入,得到新的式子:
L
o
(
μ
o
,
ϕ
o
)
=
∫
ϕ
i
=
0
2
π
∫
μ
i
=
0
1
f
(
μ
i
,
ϕ
i
,
μ
o
,
ϕ
o
)
L
i
(
μ
i
,
ϕ
i
)
μ
i
d
μ
i
d
ϕ
i
(9.6)
L_o(\mu_o,\phi_o) = \int^{2\pi}_{\phi_i=0}\int^{1}_{\mu_i=0}f(\mu_i,\phi_i,\mu_o,\phi_o)L_i(\mu_i,\phi_i)\mu_i d\mu_i d\phi_i\tag{9.6}
Lo(μo,ϕo)=∫ϕi=02π∫μi=01f(μi,ϕi,μo,ϕo)Li(μi,ϕi)μidμidϕi(9.6)
关于BRDF函数,基于基本的物理规律,它有两种限制:
- Helmholtz互异性(Helmholtz Reciprocity):它表示将入射光的方向和观察者方向互调,BRDF得到的反射率是一样的,即
f ( l , v ) = f ( v , l ) (9.7) f(\textbf{l}, \textbf{v})=f(\textbf{v}, \textbf{l})\tag{9.7} f(l,v)=f(v,l)(9.7) - 能量守恒定律:即反射光的强度小于等于到该点的入射光强度
因为能量守恒的制约,光能量在反射方向上是可能有损失的。有一个函数是用来衡量某点的入射光经过反射之后的损失率,这个函数就是定向半球反射(directional-hemispherical reflectance),记为
R
(
l
)
=
∫
v
∈
Ω
f
(
l
,
v
)
(
n
,
l
)
d
l
(9.8)
R(\textbf{l})=\int_{v\in \Omega}f(\textbf{l},\textbf{v})(\textbf{n},\textbf{l})d\textbf{l}\tag{9.8}
R(l)=∫v∈Ωf(l,v)(n,l)dl(9.8)
它得到的是特定入射方向上的光在所有反射方向上的反射光强度之和,它的值域为[0, 1],正是能量守恒的体现。同时因为不同波长的光的
R
(
l
)
R(l)
R(l) 不同,所以在渲染上,它的值是一个RGB三维向量,代表着三种波长的光在该物体表面的
R
(
l
)
R(l)
R(l),BRDF函数亦是如此。
一个最简单的BRDF例子就是兰伯特光照模型。兰伯特光照模型的BRDF函数是一个常量,它表示入射到物体表面之后反射的光在任意的反射方向上都具有同样的能量。将常量BRDF函数带入式 (9.8) 兰伯特光照模型的定向半球反射函数也是一个常量:
R
(
l
)
=
π
f
(
l
,
v
)
(9.10)
R(\textbf{l})=\pi f(\textbf{l}, \textbf{v})\tag{9.10}
R(l)=πf(l,v)(9.10)
理解BRDF的最好的方式就是将BRDF可视化:
实心绿色线条是入射光线,绿色虚线是理想的反射方向,两个白色线条分别是入射光线在平面的投影和法线。
左上:兰伯特光照模型,因为BRDF是一个常量,所以在所有方向上的强度都相等。中上:Blinn-Phong光照模型,Blinn-Phong对高光有着很好的描述,高光的模拟依靠在理想反射方向上有很高的反射率,而其它方向的强度则被削弱了。右上:Cook-Torrance光照模型,对镜面反射有很好的描述,需要注意的是Cook-Torrance的镜面反射最强的方向和理想反射方向并不重合。左下:Ward各向异性模型。中下:Hapke/Lommel-Seeliger的“月球表面” 模型,正如其名,这个模型与月球表面的光散射特性研究有关。右下:Lommel-Seeliger散射模型。