DongGu
光线追踪加速结构

光线追踪加速结构

前面我们介绍了基础的 Whitted-Style 光线追踪模型,其中光线需要与场景中的所有三角形逐一求交。虽然渲染结果很真实,但速度极慢 — 对于包含百万三角形的场景,每一条光线都要做百万次求交测试。本文将介绍各类光线追踪加速结构,通过空间划分和层次包围盒大幅减少不必要的求交计算,显著提升渲染速度。

轴对齐包围盒(AABB)

包围盒

我们在光栅化阶段已经接触过包围盒的概念 — 它就是一个紧凑的、完全包裹住几何形体的盒子。

在光线追踪中引入包围盒可以实现显著的加速效果:如果光线连包围盒都碰不到,那它绝不可能碰到包围盒内部的任何三角形,可以直接跳过该包围盒内的所有求交计算。

AABB 轴对齐包围盒

在光线追踪中,为了方便计算,我们使用一种特殊的包围盒 — AABB(Axis-Aligned Bounding Box,轴对齐包围盒)。这个长方体的所有面都平行于三维坐标轴( 轴)。

光线与 AABB 求交

光线与 AABB 求交

我们先从二维情况入手,原理可以直接推广到三维。

轴方向:光线撞上左墙()和右墙()的时间分别为

轴方向:光线撞上底墙()和顶墙()的时间分别为

t 的计算

关于 的计算,因为我们的包围盒是轴对齐的,可以直接通过向量在对应轴上的分量来计算该方向上的 。例如 方向:

其他方向上的 同理。

真正进入盒子的时间(:必须等所有轴向都进入才算进入,所以要取所有进入时间的最大值:

真正离开盒子的时间(:只要有一个轴向穿出去了,光线就离开盒子,所以要取所有离开时间的最小值:

最后,穿过包围盒的判定条件是:

特殊情况分析:

  • 如果 :说明盒子在光线起点的背面(时间为负),光线向前方射击是碰不到它的。
  • 如果 :说明 在背后(光线起点在盒子内部), 在前面 — 此时光线起点就在盒子内部,当然算击中了包围盒。

如果你对前面介绍的直线裁剪算法还有印象,这个求交思路其实与 Liang-Barsky 算法如出一辙。

推广到三维,只需增加 方向的计算:

空间划分

有了 AABB 作为基础单元,我们可以将整个场景空间划分为多个包围盒,构建层次结构来加速光线追踪。

均匀网格(Uniform Grid)

均匀网格

做法:把整个 3D 场景切成一个个大小完全相同的正方体格子。每个格子记录自己内部包含哪些三角形。

遍历:光线像直线一样穿过这些格子,遇到哪个格子有物体,就只和那个格子里的三角形求交。

缺点:遇到”体育场里放一根针”的场景(大片的空旷空间,物体集中在一小块区域)时,格子太粗则加速效果甚微,格子太细则内存爆炸。这种均匀划分无法适应场景中几何体分布的不均匀性。

KD-Tree(K-Dimensional Tree)

KD-Tree 空间划分

KD-Tree 采用自适应空间划分,根据几何体分布非均匀地切分空间。

做法

  1. 拿到当前节点的大包围盒。
  2. 沿 轴将空间分成两半。
  3. 对两个子空间,沿 轴分别分成两半。
  4. 对子空间沿 轴分别分成两半……如此 循环往复,直到节点内的三角形数量低于预设阈值。

遍历:光线从根节点开始测试,如果命中,就沿着树结构去检测左右子节点,无需处理未被光线穿过的子树。

缺点:因为 KD-Tree 划分的是空间而非物体,一个三角形可能跨越划分平面,同时被多个节点包含。这会导致同一个三角形被重复存储、重复求交,增加了内存开销和计算冗余。

BVH(Bounding Volume Hierarchy,层次包围盒)

BVH 层次包围盒

BVH 同样是树状结构,但与 KD-Tree 的根本区别在于:BVH 划分的是物体,而不是空间。

做法

  1. 拿到当前节点的大包围盒。
  2. 将节点内的三角形按 轴坐标排序,取中位数作为划分点,使两个子节点包含的三角形数量基本相等。
  3. 对两个子节点,按 轴坐标分别做同样的排序与划分。
  4. 对子节点按 轴坐标分别划分……如此 循环往复,直到节点内的三角形数量低于预设阈值。

遍历:光线从根节点开始测试,命中了就去检测左右子节点,未命中则剪枝跳过。

优点:因为划分的是物体而非空间,每个三角形只属于一个节点,不存在 KD-Tree 中的重复存储问题。

BVH 的缺点

缺点:如上图所示,简单的数量中位数划分(Median Split)对于”一堆三角形极小且密集、另一堆三角形极大且稀疏”的场景并不高效。小三角形会被迫与大三角形共享同一个包围盒,而该包围盒体积极大,容易被光线命中,导致光线需要频繁计算与大包围盒内大量小三角形的相交 — 这正是 SAH 要解决的问题。

SAH(Surface Area Heuristic,表面积启发式)

SAH 同样是对几何物体进行划分,但为了解决 BVH 中位数划分的缺陷,SAH 定义了一个开销函数(Cost Function),并在每次切分时选择开销最小的划分方式,而非简单地按数量平分。

开销函数

其中:

  • :光线遍历一个内部节点(判断是否命中包围盒、指针跳转)的固定开销。
  • :光线与单个三角形求交的固定开销。
  • :切分后,子节点 和子节点 各自包含的三角形数量。
  • :在光线命中当前包围盒的前提下,进一步命中子节点 和子节点 的概率。

概率的几何解释

根据几何概率,在三维空间中,如果一个大包围盒内包裹着一个小包围盒,那么一束随机光线在命中大盒子的前提下,命中内部小盒子的概率,恰好等于它们的表面积之比。直观理解:表面积越大,“接住”光线的机会就越大。

因此:

其中 是子节点包围盒的表面积, 是父节点包围盒的表面积。

代入开销函数,得到最终的 SAH 代价公式:

做法

SAH 的核心是用开销函数指导划分。与 BVH 的简单中位数平分不同,SAH 在每次切分时会评估多种候选划分方案,选择使开销函数最小的那个。为了在合理时间内找到近似最优解,SAH 通常采用分桶法(Binning)

SAH 分桶法
  1. 拿到当前节点的大包围盒。
  2. 将节点内的三角形按 轴坐标排序(下一次划分用 ,再下一次用 ,如此 循环)。
  3. 将坐标范围等距划分为若干个桶(Bucket,通常取 8~32 个),将每个三角形按其质心位置分配到对应的桶中。
  4. 依次计算在每个桶边界处切分的 SAH 开销,选择开销最小的边界位置作为最终的划分平面。
  5. 对两个子节点递归重复上述操作,直到节点内的三角形数量低于预设阈值。

通过分桶法,SAH 能够在 的时间内构建出高质量的 BVH 树,在渲染时显著减少光线与三角形的求交次数,是目前工业界光线追踪加速结构的事实标准。

遍历:与 BVH 完全相同 — 光线从根节点开始测试,命中了就去检测左右子节点,未命中则剪枝跳过。SAH 与 BVH 的区别仅在于树的构建阶段,运行时遍历逻辑一致。

缺点:构建开销高于简单 BVH。每次划分都需要评估多个候选位置的开销函数,尤其是分桶和排序会引入额外的预处理时间。但对于静态场景(构建一次、追踪海量光线),这部分构建开销会被后续的渲染加速完全摊还。

总结

本文介绍了光线追踪中用于加速求交的各类空间结构:

  1. AABB(轴对齐包围盒):最基础的加速单元,利用轴对齐特性可以极高效地计算光线与包围盒的交点(仅需分量除法)。核心判定公式为
  2. 均匀网格:将空间均匀切分为格子,实现简单但对非均匀分布的几何体效率低下。
  3. KD-Tree:自适应空间划分,按 循环切分空间。缺点是同一三角形可能跨越多个节点。
  4. BVH(层次包围盒):划分物体而非空间,每个三角形只属于一个节点,解决了 KD-Tree 的冗余问题。但简单的数量中位数划分在几何体分布不均时效率不佳。
  5. SAH(表面积启发式):通过开销函数和表面积概率模型,选择代价最小的切分位置。结合分桶法,可在 时间内构建出高质量的 BVH,是目前工业界的主流方案。

这些加速结构使得原本复杂度为 的蛮力求交,降低到 的水平,是光线追踪从离线渲染走向实时渲染的关键技术。


这次的插图来自画师 luoyu

图片地址:https://www.pixiv.net/artworks/116827009

本文作者:DongGu
本文链接:https://donggu.xyz/2026/06/18/图形学入门/光线追踪加速结构/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可