GAMES102 Lecture 16 Ray Tracing 4
这里回顾GAMES101 Lecture 16,蒙特卡洛积分与路径追踪。
课程主页:
课程作业:
课程视频:
本讲内容
- 简要回顾
- 蒙特卡洛积分
- 路径追踪
蒙特卡洛积分
蒙特卡洛法是求解定积分的一种方法,即对于定积分:
考虑随机变量:
那么有蒙特卡洛估计器:
我们来计算$F_N$的数学期望:
特例
考虑均匀分布:
此时蒙特卡洛估计器为:
一些笔记
- 采样点越多,方差越小;
- 蒙特卡洛积分关于$x$采样,关于$x$积分;
路径追踪
动机
Whitted-Style光线追踪:
- 始终执行镜面反射/折射;
- 在漫反射表面停止反射;
这些简化合理吗?
- 让我们逐步改进Whitted-Style的光线追踪并引入我们的路径追踪算法!
Whitted-Style光线追踪问题
对于有光泽的材质,光线应该在哪里反射?
diffuse物体没有反射?
所以Whitted-Style光线追踪是错误的,正确的是渲染方程:
那么接下来是如何求解该方程,注意到该方程设计:
- 求解半球上的积分;
- 递归定义;
蒙特卡洛法
对于第一点,我们利用之前介绍的蒙特卡洛积分进行求解。假设我们要在以下场景中渲染一个像素(点),$\omega_o$是观测点,光源的方向为$\omega_i$:
我们忽略发光项,那么渲染方程为:
为了使用蒙特卡洛法,我们选择$f(x)$和pdf:
- $f(x)=L_i\left(p, \omega_i\right) f_r\left(p, \omega_i, \omega_o\right)\left(n \cdot \omega_i\right)$
- $g\left(\omega_i\right)=1 / 2 \pi$
- 我们选择在半球上均匀采样;
那么:
伪代码:
shade(p, wo)
Randomly choose N directions wi~pdf
Lo = 0.0
For each wi
Trace a ray r(p, wi)
If ray r hit the light
Lo += (1 / N) * L_i * f_r * cosine / pdf(wi)
Return Lo
引入全局照明
让我们再进一步:如果光线打到物体会发生什么?
上图中$Q$将光线反射到$P$,那么$P$点的Incident Radiance即为$Q$点的Incident Radiance,所以伪代码可以改进为:
shade(p, wo)
Randomly choose N directions wi~pdf
Lo = 0.0
For each wi
Trace a ray r(p, wi)
If ray r hit the light
Lo += (1 / N) * L_i * f_r * cosine / pdf(wi)
Else If ray r hit an object at q
Lo += (1 / N) * shade(q, -wi) * f_r * cosine / pdf(wi)
Return Lo
问题
上述算法有两个问题:
- 光线数量随着反射次数呈指数增加:
- $# \text { rays }=N^{ #bounces }$
- 算法是递归算法,但是没有终止条件;
问题1
对于第一个问题,我们选择的方式是选择$N=1$,即每次只考虑一根光线,此时代码为:
shade(p, wo)
Randomly choose ONE direction wi~pdf(w)
Trace a ray r(p, wi)
If ray r hit the light
Return L_i * f_r * cosine / pdf(wi)
Else If ray r hit an object at q
Return shade(q, -wi) * f_r * cosine / pdf(wi)
注意,这就是路径追踪,$N\neq1$的情形为分布式路径追踪。
该方法可能会噪声较大,但实际中没有什么问题,因为我们需要对每个像素求radiance,而每个像素会有很多个光线穿过,只需通过每个像素追踪更多路径并平均它们的radiance即可:
光线生成
上述描述也为光线生成的过程:
ray_generation(camPos, pixel)
Uniformly choose N sample positions within the pixel
pixel_radiance = 0.0
For each sample in the pixel
Shoot a ray r(camPos, cam_to_sample)
If ray r hit the scene at p
pixel_radiance += 1 / N * shade(p, sample_to_cam)
Return pixel_radiance
问题2
为了解决第二个问题,我们需要引入Russian Roulette (RR) (俄罗斯轮盘赌):
- 以$0<P<1$的概率成功;
- 以$1-P$的概率失败;
现在假设我们手动设置一个概率$P(0<P<1)$:
以概率$P$,发射一条光线,返回着色结果除以$P$:$L_o/P$;
以概率$1-P$,不发射一条光线,你会得到$0$;
此时期望仍然为$L_o$:$E=P ( { L_o } / P)+(1-P) 0=\text { Lo }$
算法
shade(p, wo)
Manually specify a probability P_RR
Randomly select ksi in a uniform dist. in [0, 1]
If (ksi > P_RR) return 0.0;
Randomly choose ONE direction wi~pdf(w)
Trace a ray r(p, wi)
If ray r hit the light
Return L_i * f_r * cosine / pdf(wi) / P_RR
Else If ray r hit an object at q
Return shade(q, -wi) * f_r * cosine / pdf(wi) / P_RR
路径追踪问题
现在我们已经有了正确版本的路径追踪,但是不高效:
不高效的原因是,当光源很小时,需要发射很多光线才能打到光源,即如果我们在阴影点对半球进行均匀采样,就会“浪费”很多光线:
这里的关键点在于,我们是对着光线进行采样,如果对光源采样则可以避免这点,注意此时做变量替换,首先注意光线和着色点的关系:
我们考虑立体角,那么有:
此时积分公式为:
现在我们考虑来自两个部分的辐射(RR表示俄罗斯轮盘赌):
- 光源(直接,无需RR);
- 利用刚刚介绍的公式;
- 其他反射器(间接,RR);
此时算法为:
shade(p, wo)
# Contribution from the light source.
Uniformly sample the light at x’ (pdf_light = 1 / A)
L_dir = L_i * f_r * cos θ * cos θ’ / |x’ - p|^2 / pdf_light
# Contribution from other reflectors.
L_indir = 0.0
Test Russian Roulette with probability P_RR
Uniformly sample the hemisphere toward wi (pdf_hemi = 1 / 2pi)
Trace a ray r(p, wi)
If ray r hit a non-emitting object at q
L_indir = shade(q, -wi) * f_r * cos θ / pdf_hemi / P_RR
Return L_dir + L_indir
最后一个问题
如果有物体遮挡该怎么办?判断物体是否在光源和着色点之间即可:
算法:
# Contribution from the light source.
L_dir = 0.0
Uniformly sample the light at x’ (pdf_light = 1 / A)
Shoot a ray from p to x’
If the ray is not blocked in the middle
L_dir = …
效果展示
最后展示一下效果:
我们没有覆盖/不会覆盖的内容
- 对半球进行均匀采样
- 如何? 一般来说,如何对任何函数进行采样?
(采样)
- 如何? 一般来说,如何对任何函数进行采样?
- 蒙特卡洛积分允许任意pdf
- 最好的选择是什么? (重要度抽样)
- 随机数重要吗?
- 是的! (低偏差序列)
- 可以采样半球和光线
- 我可以把它们结合起来吗? 是的!(multiple imp. sampling )
- 一个像素的辐射度是通过它的所有路径的辐射度平均值吗?
- 为什么? (像素重构滤波器)
- 像素的radiance 是像素的颜色吗?
- 不是(伽马校正、曲线、色彩空间)