GAMES102 Lecture 13 Ray Tracing 1 (Whitted-Style Ray Tracing)
这里回顾GAMES101 Lecture 13,这一讲介绍了光线追踪(基本原理)。
课程主页:
课程作业:
课程视频:
为什么需要光线追踪?
- 光栅化无法很好地处理全局效果:
- (软)阴影;
- 光线反射多次;
- 光栅化速度很快,但质量相对较低;
- 光线追踪很准确,但速度很慢;
- 光栅化:实时;
- 光线追踪:离线;
- 大约10K CPU核心小时在产品中渲染一帧;
基本光线追踪算法
光线
关于光线的三个想法(图形学中的基本假设):
- 光以直线传播(虽然这是错误的);
- 光线交叉时不会相互“碰撞”
(虽然这仍然是错误的); - 光线从光源传播到眼睛(可逆性,也可以理解为光线从眼角传播到光源);
光线投射
基本流程:
- 对每像素投射一条射线来生成图像;
- 通过(从图像)向灯光发送光线来检查阴影;
这里有几个基本假设:
- 假设眼睛是一个点;
- 光源是点光源;
产生eye ray
结合上图进行讲解:
- 首先从眼睛出发一个光线,穿过pixel,指向物体;
- 找到光线和场景内最近的物体的交点(因为该交点会遮挡后续交点);
- 从该交点向光源连线;
- 根据入射,出射,法线方向计算着色;
注意到该方法认为光线只弹射一次,所以效果和光栅化产不多,为了解决这点,需要引入Recurisive (Whitted-Style)光线追踪,效果为:
Recurisive光线追踪
依然考虑光线投射。当光打到玻璃球上,会发生反射和折射,折射光线会再次发生反射和折射,这个过程会发生无限多次,我们在每个弹射点计算着色结果,最后将其累加到像素上:
这来再对光线进行分类:
- primary ray:从眼角直接发射的光线;
- secondary ray:弹射后的光线;
- shadow rays:向光源连接的光线;
上述是整体思路,下面介绍该算法的细节,从光线和表面交点开始。
光线-表面交点
光线方程
光线是一条射线,由起点和方向定义:
其中:
- $\mathbf o$是起点;
- $\mathbf d$是单位方向向量;
图示:
光线和球面的交点
球面方程为:
求交点即为求解如下方程:
展开后可得:
那么:
判别式$<0, =0, >0$分别对应没有交点,一个交点和两个交点的情形。
光线和显式表面的交点
对球面的情形进行推广,对于一般的显式表面:
我们求解如下方程的正实数解:
光线和三角形面的交点
为什么要讨论光线和三角形的交点?
- 渲染:可见性,阴影,灯光 ;
- 几何:光线内部/外部测试;
- 对于封闭的曲面,如果一个射线和该曲面有奇数个交点,则在曲面内,否则在曲面外;
如何计算?
让我们分解一下:
- 简单的想法:只需将射线与每个三角形相交;
- 简单但缓慢(如何加速?);
- 注意:可以有0或1个交点
(忽略多个交点情形);
光线和三角形的交点
注意到三角形在某个平面内,所以将该问题分解为两个步骤:
- 求解光线和平面的交点;
- 判断交点是否在三角形内;
平面方程
平面有平面上一个点和法向量定义:
平面方程:
标准形式为:
将光线方程$\mathbf{r}(t)=\mathbf{o}+t \mathbf{d}, 0 \leq t<\infty$代入可得:
求解后再检查是否满足$0\le t<\infty$以及交点是否在三角形内。
Möller Trumbore算法
Möller Trumbore算法利用重心坐标进行求解:
变形可得:
记:
那么方程变换为:
两边点乘法$\mathbf S_1$可得:
两边点乘$\mathbf S_2$可得:
两边点乘${\mathbf{E} }_1\times \mathbf E_2$可得:
注意到:
所以:
根据$t$和$b_2$的关系可得:
即:
加速光线和表面交点的计算
光线追踪——性能挑战
简单的光线场景相交
- 详尽地测试每个三角形的光线交点;
- 找到最近的命中(即最小$t$)
;
问题:
- 朴素算法 = #pixels ⨉ #traingles (⨉ #bounces)
- 非常慢!
为了一般性,我们稍后使用术语对象而不是三角形(但不一定表示整个对象)
包围盒
避免交点的快速方法,用简单的体积包围复杂的对象:
- 对象完全包含在盒中;
- 如果光线不和盒相交,光线就不会和对象相交;
- 所以首先测试BVol,然后测试对象是否相交;
图示:
光线与盒子的交点
- 长方体的理解:box是3对平行面形成的交集;
- 具体来说:
我们经常使用Axis-Aligned Bounding Box (AABB) (轴对齐包围盒)
,即BB的任何一侧都沿x、y或z轴;
光线和Axis-Aligned Box的交点
计算与平行面的交点,并取tmin/tmax区间的交集(以2D为例):
求出光线关于x平面和y平面的进入和离开的时间$t_{\mathrm{min} }/t_{\mathrm{max} }$,对两次求得的区间$[t_{\min}, t_{\max}]$求交集。
对于3D盒子 = 三对无限大的平板,关键思想为:
- 光线只有在进入所有成对的平板时才会进入盒子;
- 只要光线离开任何一对平板,光线就会离开盒子;
- 所以对于每一对平板,计算tmin和tmax(负数也ok)
- 对于3D box,$t_{\mathrm{enter} } = \max{t_{\min} } $,$t_{\mathrm{exit} } = \min{t_{\max} }$
- 如果$t_{\mathrm{enter} } < t_{\mathrm{exit} }$,我们知道光线在盒子里停留了一段时间(所以必须相交!);
- 然而,射线不是直线;
- 应该检查$t$对应的实际情形是否正确;
- 如果$t_{\mathrm{exit} }$怎么办?
- 盒子在光线“后面”——没有交点!
- 如果$t_{\mathrm{exit} }\ge 0$并且$t_{\mathrm{enter} }<0$怎么办?
- 光线的起点在盒子内——有交点!
- 综上所述,ray和AABB当且仅当:
- $t_{\mathrm{enter} } < t_{\mathrm{exit} }$并且$t_{\mathrm{exit} }\ge 0$;
为什么要使用轴对齐
最后一个问题,为什么要使用轴对齐包围盒?原因很简单,为了计算方便。
对于一般情形:
公式
对于轴对齐情形:
公式: