本文未经允许禁止转载
B站:https://space.bilibili.com/455965619
作者:
Heskey0
/ 赫斯基皇
二.specular材质和glass材质
在这个案例中,总共有4种材质
none
specular
glass
lambertian
注意:由于每种材质的复杂度不同,我会分开介绍这些材质中如何实现能量守恒
1.specular材质
对于specular材质,我们 不考虑折射,只考虑反射
(1) 我们首先对出射光的方向进行采样
def reflect(d, n):
# d and n are both normalized
ret = d - 2.0 * d.dot(n) * n # d - 2*|d|*|n|*n*cos<d,n>(theta) = d - 2 |d|*cos(theta) * (n/|n|)
return ret
代码的原理很简单,就是初中学习的 光的反射
(2) 计算pdf值
由于 只考虑反射,所以 pdf=1
2.glass材质
glass材质 既要考虑反射,也要考虑折射
(1) 我们首先对出射光的方向进行采样
对于 反射, 可按照上面specular材质的计算方式计算出出射光方向
对于 折射,我们需要利用高中学习的 光的折射
def refract(d, n, ni_over_nt):
dt = d.dot(n)
discr = 1.0 - ni_over_nt * ni_over_nt * (1.0 - dt * dt) # discr:折射角的cos
rd = (ni_over_nt * (d - n * dt) - n * ti.sqrt(discr)).normalized()
return rd
注意: 不同于specular材质,我们还需要考虑一个问题:
入射光的能量 = 反射光的能量 + 折射光的能量。那么,拆分后的能量的关系是什么?
对于这个问题,我们需要运用 《PBRT》
第八章提到的菲涅尔反射的能量公式
我们先求出反射比
r0
r0 = (1.0 - eta) / (1.0 + eta)
r0 = r0 * r0
然后根据
schlick
近似公式计算brdf
r0 + (1 - r0) * ((1.0 - cos)**5)
我们回忆brdf
的概念,brdf
表示的是 表面反射微分辐射率和入射微分辐照度的比率,辐射率是 通过单位面积单位立体角的辐射通量。而在glass材质中,反射光是集中的,不需要想漫反射那样去做半球采样,反射光就是位于单位立体角。
所以,这里得到的brdf
的值,就可以直接作为我们分配 反射能量与折射能量的比率。所以我们就可以写出下列代码,利用random
进行光照能量的分配。
refl_prob = schlick(cos, refr_idx)
if ti.random() < refl_prob: # 反射
u = reflect(indir, normal)
else: # 折射
u = refract(indir, outn, ni_over_nt)
当
random
的值小于这个比率的时候,我们按照反射处理
当random
的值大于这个比率的时候,我们按照折射处理
(2) 计算pdf
由于是glass材质,所以不需要进行半球采样,故pdf = 1
。