AABB加速光线追踪
1.包围盒(Bounding Volumes)
遇到非常复杂的场景,三角形面数太多,且光线复杂,将会花费大量时间来渲染。如下图有着10.7万个三角形面:
因此,引入包围盒(Bounding Volumes)
将物体包围在有一定范围内,如果射线没有击中包围盒,那么它就不会击中物体。过程很简单:光线有打到盒体上,那么再去计算光线与物体表面的交点。
包围盒定义:一个包围盒由三对平行面包围而形成的一个三维空间中的区域:
1.1轴对齐包围盒Axis-Aligned Bounding Box (AABB)
我们通常使用轴对齐包围盒Axis-Aligned Bounding Box (AABB) :
为什么要轴对齐?
如下图所示,明显在计算难度上,用了轴对称后的会更简单计算:
1.2AABB计算交点的具体步骤
Step1:在x,y平面上分别求出光线经过两对平行面的进入时间
t
(
m
i
n
)
t(min)
t(min)和出去时间
t
(
m
a
x
)
t(max)
t(max)
Step2:在整体区域上,光线进入该区域的时间取两个
t
(
m
i
n
)
t(min)
t(min)中的最小值,出去该区域的时间取
t
(
m
a
x
)
t(max)
t(max)中的最大值(
t
t
t可以取负数)
对于3D盒体:
- 3D物体的包围盒盒体就是一个三对无限大的平板
- 只有光线同时进入所有相对的面才算进入盒体
- 只有光线从一个相对面中出去才算离开盒体
- 对于每对面,求 t m i n , t m a x t_{min},t_{max} tmin,tmax(负值情况后面介绍)
- 然后,对于整个盒体, t e n t e r = m a x ( t m i n ) , t e x i t = m a x ( t m i n ) t_{enter}=max(t_{min}),t_{exit}=max(t_{min}) tenter=max(tmin),texit=max(tmin)
- 当 t e n t e r < t e x i t t_{enter}<t_{exit} tenter<texit时,认为光线进入了盒体
如果 t m i n , t m a x t_{min},t_{max} tmin,tmax出现了负数:
- 光线不是直线
- 当 t e x i t < 0 t_{exit}<0 texit<0时,盒体在阴影中,即与光线没有交点
- 当 t e x i t ≥ 0 t_{exit}\geq0 texit≥0时,光线起点在盒体内,有交点
- 总之,光线与AABB相交,当且仅当 t e n t e r < t e x i t & t e x i t ≥ 0 t_{enter}<t_{exit} \& t_{exit}\geq0 tenter<texit&texit≥0
2.AABB加速光线追踪
2.1均匀空间划分
在之前包围盒的基础上,做了进一步均匀空间划分,
具体步骤:
Step1:创建包围盒包围物体
Step2:均分网格(网格大小与实际物体数量有关,测试出来网格数量一般为 27
×
\times
×物体数量)
Step3:将每个对象存储在其所占有单元格中
Step4:将光线入射,先判断是否经过物体所占的单元格
Step5:若经过物体所占的单元格,再判断是否与物体所占的单元格相交
注:判断光线经过了哪些网格时,不需要遍历全部网格,如下图所示,光线是从左下到右上,则光线所经过的下一个网格,一定在当前网格的上方或者右方
但是,这种将空间均分的方法,也有其局限性,并不能适应大多数情况,如下图所示:
适用于:大小和空间上均匀分布的大型对象集合
不适用于:分布极不均匀的物体
2.2空间划分(KD-Tree)
由于上述方法是均匀划分空间的,不能很好的将物体放在一个单元格中,因此我们提出空间划分的方法,为了能够将一个或更多物体整体的放在一个格子里面。
Oct-Tree(八叉树):将包围盒
x
,
y
,
z
x,y,z
x,y,z方向"各切一刀"一分为八(等区域),然后在切出来的各个子盒中再次一分为八,直至子包围盒中没有物体,存在高维度不好划分的问题;
KD-Tree(类似二叉树):下面再详细介绍;
BSP-Tree(类似二叉树):和KD-Tree思想一样,只是将水平切和竖直切,变成了斜着切,并且不符合AABB规则,存在高维度不好划分的问题;
2.2.1 KD-Tree
Step1:划分网格,保存信息
对包围盒进行有规律的划分(例如:按顺序沿着x、y、z轴进行依次划分),当子盒体中物体数量很少时,该子盒体就得停止划分;最后将物体的各种信息都保存在自己所在的最小盒体所对应的叶子节点上,如下图所示:
注:例子只划分了右半部分,实际上左右部分都需要划分,这里仅以右边为例
Step2:依次遍历KD-Tree子节点判断是否相交,如果相交则继续与其子节点判断,直到叶子节点,再去与叶子节点内存储的物体求交点
直至:
KD-Tree存在的问题:
- 判断物体与包围盒边界的相交关系的算法较难,不容易写出;
- 一个物体可能在多个包围盒内,那么就会有多个叶子结点包含此物体信息;
2.3对物体划分(BVH方法)
BVH是基于三角形面进行空间划分的光追加速算法。
具体步骤:
Step1:首先将场景中的物体用一个大的AABB包起来
Step2:将大的AABB再次依据物体分布,分为两个小的AABB(可能会重叠,但不影响);人为规定停下的要求(比如盒内物体数量小于等于3时)
注:例子只划分了左半部分,实际上左右部分都需要划分,这里仅以左边为例
注:
- 每次划分尽量选择最长轴x,y,z轴进行划分,这样可以保证每次划分在空间上较平均
- 尽量选择中间节点进行划分,这样可以保证划分出来的二叉树无限接近于平衡二叉树
BVH伪代码: