光线追踪加速结构
前面我们介绍了基础的 Whitted-Style 光线追踪模型,其中光线需要与场景中的所有三角形逐一求交。虽然渲染结果很真实,但速度极慢 — 对于包含百万三角形的场景,每一条光线都要做百万次求交测试。本文将介绍各类光线追踪加速结构,通过空间划分和层次包围盒大幅减少不必要的求交计算,显著提升渲染速度。
轴对齐包围盒(AABB)
我们在光栅化阶段已经接触过包围盒的概念 — 它就是一个紧凑的、完全包裹住几何形体的盒子。
在光线追踪中引入包围盒可以实现显著的加速效果:如果光线连包围盒都碰不到,那它绝不可能碰到包围盒内部的任何三角形,可以直接跳过该包围盒内的所有求交计算。
在光线追踪中,为了方便计算,我们使用一种特殊的包围盒 —
AABB(Axis-Aligned Bounding
Box,轴对齐包围盒)。这个长方体的所有面都平行于三维坐标轴(
光线与 AABB 求交
我们先从二维情况入手,原理可以直接推广到三维。
在
在
关于
其他方向上的
真正进入盒子的时间(
真正离开盒子的时间(
最后,穿过包围盒的判定条件是:
特殊情况分析:
- 如果
且 :说明盒子在光线起点的背面(时间为负),光线向前方射击是碰不到它的。 - 如果
且 :说明 在背后(光线起点在盒子内部), 在前面 — 此时光线起点就在盒子内部,当然算击中了包围盒。
如果你对前面介绍的直线裁剪算法还有印象,这个求交思路其实与 Liang-Barsky 算法如出一辙。
推广到三维,只需增加
空间划分
有了 AABB 作为基础单元,我们可以将整个场景空间划分为多个包围盒,构建层次结构来加速光线追踪。
均匀网格(Uniform Grid)
做法:把整个 3D 场景切成一个个大小完全相同的正方体格子。每个格子记录自己内部包含哪些三角形。
遍历:光线像直线一样穿过这些格子,遇到哪个格子有物体,就只和那个格子里的三角形求交。
缺点:遇到”体育场里放一根针”的场景(大片的空旷空间,物体集中在一小块区域)时,格子太粗则加速效果甚微,格子太细则内存爆炸。这种均匀划分无法适应场景中几何体分布的不均匀性。
KD-Tree(K-Dimensional Tree)
KD-Tree 采用自适应空间划分,根据几何体分布非均匀地切分空间。
做法:
- 拿到当前节点的大包围盒。
- 沿
轴将空间分成两半。 - 对两个子空间,沿
轴分别分成两半。 - 对子空间沿
轴分别分成两半……如此 循环往复,直到节点内的三角形数量低于预设阈值。
遍历:光线从根节点开始测试,如果命中,就沿着树结构去检测左右子节点,无需处理未被光线穿过的子树。
缺点:因为 KD-Tree 划分的是空间而非物体,一个三角形可能跨越划分平面,同时被多个节点包含。这会导致同一个三角形被重复存储、重复求交,增加了内存开销和计算冗余。
BVH(Bounding Volume Hierarchy,层次包围盒)
BVH 同样是树状结构,但与 KD-Tree 的根本区别在于:BVH 划分的是物体,而不是空间。
做法:
- 拿到当前节点的大包围盒。
- 将节点内的三角形按
轴坐标排序,取中位数作为划分点,使两个子节点包含的三角形数量基本相等。 - 对两个子节点,按
轴坐标分别做同样的排序与划分。 - 对子节点按
轴坐标分别划分……如此 循环往复,直到节点内的三角形数量低于预设阈值。
遍历:光线从根节点开始测试,命中了就去检测左右子节点,未命中则剪枝跳过。
优点:因为划分的是物体而非空间,每个三角形只属于一个节点,不存在 KD-Tree 中的重复存储问题。
缺点:如上图所示,简单的数量中位数划分(Median Split)对于”一堆三角形极小且密集、另一堆三角形极大且稀疏”的场景并不高效。小三角形会被迫与大三角形共享同一个包围盒,而该包围盒体积极大,容易被光线命中,导致光线需要频繁计算与大包围盒内大量小三角形的相交 — 这正是 SAH 要解决的问题。
SAH(Surface Area Heuristic,表面积启发式)
SAH 同样是对几何物体进行划分,但为了解决 BVH 中位数划分的缺陷,SAH 定义了一个开销函数(Cost Function),并在每次切分时选择开销最小的划分方式,而非简单地按数量平分。
开销函数
其中:
:光线遍历一个内部节点(判断是否命中包围盒、指针跳转)的固定开销。 :光线与单个三角形求交的固定开销。 、 :切分后,子节点 和子节点 各自包含的三角形数量。 、 :在光线命中当前包围盒的前提下,进一步命中子节点 和子节点 的概率。
概率的几何解释
根据几何概率,在三维空间中,如果一个大包围盒内包裹着一个小包围盒,那么一束随机光线在命中大盒子的前提下,命中内部小盒子的概率,恰好等于它们的表面积之比。直观理解:表面积越大,“接住”光线的机会就越大。
因此:
其中
代入开销函数,得到最终的 SAH 代价公式:
做法:
SAH 的核心是用开销函数指导划分。与 BVH 的简单中位数平分不同,SAH 在每次切分时会评估多种候选划分方案,选择使开销函数最小的那个。为了在合理时间内找到近似最优解,SAH 通常采用分桶法(Binning):
- 拿到当前节点的大包围盒。
- 将节点内的三角形按
轴坐标排序(下一次划分用 ,再下一次用 ,如此 循环)。 - 将坐标范围等距划分为若干个桶(Bucket,通常取 8~32 个),将每个三角形按其质心位置分配到对应的桶中。
- 依次计算在每个桶边界处切分的 SAH 开销,选择开销最小的边界位置作为最终的划分平面。
- 对两个子节点递归重复上述操作,直到节点内的三角形数量低于预设阈值。
通过分桶法,SAH 能够在
遍历:与 BVH 完全相同 — 光线从根节点开始测试,命中了就去检测左右子节点,未命中则剪枝跳过。SAH 与 BVH 的区别仅在于树的构建阶段,运行时遍历逻辑一致。
缺点:构建开销高于简单 BVH。每次划分都需要评估多个候选位置的开销函数,尤其是分桶和排序会引入额外的预处理时间。但对于静态场景(构建一次、追踪海量光线),这部分构建开销会被后续的渲染加速完全摊还。
总结
本文介绍了光线追踪中用于加速求交的各类空间结构:
- AABB(轴对齐包围盒):最基础的加速单元,利用轴对齐特性可以极高效地计算光线与包围盒的交点(仅需分量除法)。核心判定公式为
且 。 - 均匀网格:将空间均匀切分为格子,实现简单但对非均匀分布的几何体效率低下。
- KD-Tree:自适应空间划分,按
循环切分空间。缺点是同一三角形可能跨越多个节点。 - BVH(层次包围盒):划分物体而非空间,每个三角形只属于一个节点,解决了 KD-Tree 的冗余问题。但简单的数量中位数划分在几何体分布不均时效率不佳。
- SAH(表面积启发式):通过开销函数和表面积概率模型,选择代价最小的切分位置。结合分桶法,可在
时间内构建出高质量的 BVH,是目前工业界的主流方案。
这些加速结构使得原本复杂度为
这次的插图来自画师 luoyu
图片地址:https://www.pixiv.net/artworks/116827009