GAMES101: Lecture 16: Ray Tracing 4 (Monte Carlo Path Tracing) ppt笔记

Monte Carlo Integration

计算复杂的定积分时,通过随机采样的函数值的平均值 估计该函数的定积分

对于函数f(x)f(x)f(x)的积分∫abf(x) dx\int_a^b f(x) \, dx∫abf(x)dx,其蒙特卡洛积分表示为

1N∑i=1Nf(Xi)p(Xi) \frac{1}{N} \sum_{i=1}^N \frac{f(X_i)}{p(X_i)} N1i=1∑Np(Xi)f(Xi)

采样数量越多,误差越小

在x上采样,在x上积分

Path Tracing

前面介绍的Whitted-style ray tracing,只考虑了镜面反射和折射,并在遇到漫反射表面时停止反射光线

如左图,未考虑光线在遇到漫反射表面后的继续传播,天花板被渲染成黑色,且柱形的侧面没有与周围墙壁颜色相关的color bleeding

我们需要更符合物理规律的算法

下面围绕渲染方程进行展开

Lo(p,ωo)=Le(p,ωo)+∫Ω+Li(p,ωi)fr(p,ωi,ωo)(n⋅ωi) dωi L_o(p, \omega_o) = L_e(p, \omega_o) + \int_{\Omega^+} L_i(p, \omega_i) f_r(p, \omega_i, \omega_o) (n \cdot \omega_i) \, d\omega_i Lo(p,ωo)=Le(p,ωo)+∫Ω+Li(p,ωi)fr(p,ωi,ωo)(n⋅ωi)dωi

首先只考虑下面场景中一个像素接受到的直接照亮direct illumination的光 ,不考虑Le(p,ωo)L_e(p, \omega_o)Le(p,ωo)项

要计算定积分∫Ω+Li(p,ωi)fr(p,ωi,ωo)(n⋅ωi) dωi\int_{\Omega^+} L_i(p, \omega_i) f_r(p, \omega_i, \omega_o) (n \cdot \omega_i) \, d\omega_i∫Ω+Li(p,ωi)fr(p,ωi,ωo)(n⋅ωi)dωi

设置蒙特卡洛积分的概率密度函数pdf为p(ωi)=1/2πp(\omega_i) = 1/2\pip(ωi)=1/2π

得到定积分的计算结果

Lo(p,ωo)≈1N∑i=1NLi(p,ωi)fr(p,ωi,ωo)(n⋅ωi)p(ωi) L_o(p, \omega_o) \approx \frac{1}{N} \sum_{i=1}^N \frac{L_i(p, \omega_i) f_r(p, \omega_i, \omega_o) (n \cdot \omega_i)}{p(\omega_i)} Lo(p,ωo)≈N1i=1∑Np(ωi)Li(p,ωi)fr(p,ωi,ωo)(n⋅ωi)

初步得到path tracing的计算方式:

计算某一点反射的光时,随机采样n个入射方向,向这n个方向追踪光线

若光线到达光源,将结果加上上述公式计算出的结果

若光线到达物体,以该物体在该方向反射出的光作为上式中的Li(p,ωi)L_i(p, \omega_i)Li(p,ωi),计算公式结果加到最终结果中

这里可以把物体反射出的光看作另一种光源发出的光

伪代码如下:

复制代码
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

这种算法具有下列问题:

1.指数爆炸,需要计算的光线数量是采样数量的反弹次数次幂

因此我们假设采样次数N为1

这样只随机采样一个方向的光,没有for循环

另:采样次数不为1的算法称作分布式光线追踪Distributed Ray Tracing

而采样次数过少会带来很大噪声,我们对一个像素追踪多条路径并对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)	// 利用path tracing的函数shade
	Return pixel_radiance

2.递归算法无限递归,计算机不能做无限次的光线弹射,减少弹射次数意味着截断power

我们采用俄罗斯轮盘赌Russian Roulette

从前我们采样时,永远会向表面上的采样点发射一个光线,返回radiance LoL_oLo

现在设置一个概率P,在发射光线后,有 P 的概率返回Lo/PL_o / PLo/P,有 1-P 的概率返回 0 ,这保证了返回radiance的数学期望仍然是LoL_oLo

现在解决path tracing的效率问题

若光源面积过小,采样发出的很多条光线因不会到达光源而被浪费

对于光源发出的光线,我们不在采样点上对立体角积分,而是在光源处采样,对光源面积A积分

设置光源的pdf = 1 / A

找到dωd\omegadω和dAdAdA的数量关系,立体角的定义是区域在单位球上投影的面积,我们将光源在垂直光线上的分量等比例投射到单位球上

下面θ′\theta'θ′表示光源法线与光线的夹角

dω=dA∥x′−x∥2cos⁡θ′ d\omega = \frac{dA}{\|x' - x\|^2} \cos \theta' dω=∥x′−x∥2dAcosθ′

将dωd\omegadω代入到上面的公式,得到对光源积分的结果

Lo(x,ωo)=∫ALi(x,ωi)fr(x,ωi,ωo)cos⁡θcos⁡θ′∥x′−x∥2 dA L_o(x, \omega_o) = \int_A L_i(x, \omega_i) f_r(x, \omega_i, \omega_o) \frac{\cos \theta \cos \theta'}{\|x' - x\|^2} \, dA Lo(x,ωo)=∫ALi(x,ωi)fr(x,ωi,ωo)∥x′−x∥2cosθcosθ′dA

现在我们就把结果分为两部分:

1.光源直接照射(不考虑俄罗斯轮盘赌)

2.其他反射(indirect,考虑RR)

最后考虑光线是否被物体遮挡,得到最终path tracing算法:

复制代码
shade(p, wo)
	# Contribution from the light source.
	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 = 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

Not covered

上面的讨论未涉及很多细节:

均匀采样半球 - 带权重的半球采样

蒙特卡洛的pdf选择 - 重要性采样Importance Sampling

随机数的选择 - 低差异序列Low Discrepancy Sequences

光源与半球采样的结合 - 组合采样Multiple Importance Sampling

像素的radiance为所有路径得到radiance的平均值? - 像素重建滤波器Pixel Reconstruction Filter

像素的radiance和color的关系 - 伽马矫正gamma correction

图形学博大精深

相关推荐
xqqxqxxq1 小时前
MySQL 数据类型笔记
数据库·笔记·mysql
软件技术NINI3 小时前
盗墓笔记html+css+js 2页
css·笔记·html
XiaoYu1__3 小时前
算法进阶·其二:用欧拉路径解决“一笔画”问题并建模转化De Bruijn序列的构造问题
c++·笔记·算法·欧拉路径
智者知已应修善业3 小时前
【用D触发器组成000-001-010-011-100】2025-6-7
驱动开发·经验分享·笔记·硬件架构·硬件工程
纪念 2293 小时前
数据库基础
数据库·笔记·学习方法
AnsonNie4 小时前
处理提示“wsl: 检测到 localhost 代理配置,但未镜像到 WSL。NAT 模式下的 WSL 不支持 localhost 代理。”【笔记】
笔记
山城码农笑松哥4 小时前
Redis 8.8 新特性实操笔记:原生数组、INCREX 限流、XNACK 流处理
redis·笔记·junit
xqqxqxxq4 小时前
SQL 字段约束笔记
android·笔记·sql
神龙天舞20016 小时前
CMake构建学习笔记-通用的CMake构建脚本
笔记·学习