概念页
浮点误差与鲁棒光线求交
Floating-Point Error & Robust Ray Intersection
光线追踪中,交点的浮点误差会让次级光线(阴影、反射)从表面"下方"出发、错误地再次击中自身(自相交,俗称 shadow acne),或因偏移过大漏掉近处遮挡(漂浮的阴影)。PBRT 第 4 版 6.8 节不靠经验 "ray epsilon",而是用前向误差分析为每个交点算出保守的误差盒,再沿法线把光线原点推出误差盒,做到可证明不自相交、偏移又极小。
问题与传统做法(6.8 引言)
常见做法是给新光线设最小参数 (固定 epsilon)。但若交点在表面下方而新光线很斜,错误的再相交可能发生在离原点相当远的地方,所以 必须取得很大;取大了又会漏掉附近的真实相交,丢失阴影和反射细节(PBRT 4e 图 6.38、6.39)。
浮点误差的基本工具(6.8.1)
浮点格式本身见 数值表示与浮点数;这里只列分析误差需要的结论:
- IEEE 754 保证 和 FMA 的结果等于精确结果舍入到最近的浮点数,所以 。32 位浮点在 内间距为 ,半个间距给出机器 epsilon (本页验算)。乘除 2 的幂、、 等都是精确的。
- 误差连乘 用 Higham 的 界住(式 6.23),且商 以 为界,不能约掉。
- 例: 的绝对误差界为 ; 则约为 ,所以大量求和时从小到大排序更准。
- 乘法相对误差约 ulp,很温和;同号加法也温和;异号相加(或同号相减)在 时相对误差 ,即灾难性抵消。
- 两种做法:手工推导的前向误差分析(便宜、界更紧),以及让程序在运行时用区间类
Interval跟踪误差的运行时误差分析(方便,但对点变换来说界宽 3–6 倍、慢约 6 倍)。 - 小工具:
NextFloatUp/Down()直接对位模式加减 1(正无穷不变, 先跳到 );按位重解释必须用std::bit_cast(C++20,pbrt 自带 C++17 实现),指针强转和 union 读另一成员都是未定义行为。
各环节的误差处理
| 环节 | 问题 | PBRT 的做法 |
|---|---|---|
| 光线-包围盒(6.8.2) | 误差 $\gamma_3 | t |
| 球/圆柱判别式(6.8.3) | 球离射线原点远时 ,灾难性抵消,书中把单位球放在 400 单位外正交观察时边缘会漏交 | 改写为 ,消去误差最大的 ,再用 ;改进后球可移到约 7,500 单位外仍正确。直接用 DifferenceOfProducts() 不行,因为 自身已有误差 |
| 三角形(6.8.4) | 共享边上的漏交 | 边函数 的符号在浮点下总是正确;为 0 时用双精度重算 |
| 交点位置(6.8.5) | 的误差 $\gamma_1 | o_x |
| 变换(6.8.5) | 物体空间求交再变回来 | 精确点误差 $\gamma_3( |
| 新光线原点(6.8.6) | 原点要在表面正确一侧 | 沿法线偏移 $d= |
| 交点在原点后面(6.8.7) | 舍入让真实 的交点算成 | 平板测试的 符号天然正确;二次曲面用区间判断;三角形推导 ,要求 (场景尺度 ±10 时约 );双线性面片用基于输入量级的 epsilon |
阴影光线到面光源的问题没有解决:pbrt 把阴影光线的 设为略小于 1(ShadowEpsilon),在光源表面之前停下。
代价与比较(6.8.8、延伸阅读)
- 换用这套方法后总渲染时间约增加 20%(改用双精度约增加 30%)。增加的主要不是算误差界,而是原点离表面太近,BVH 遍历时访问的节点和求交次数变多(Wächter 2008 首先指出)——这是精度的代价。
- Wächter 也沿法线偏移,但偏移量是交点量级的固定比例;PBRT 的偏移是保守推导出的,而且通常更小。其他做法:忽略上一次击中的物体、root polishing(再求交一次)、换双精度。
- 颜色与光照计算多是正数乘积之和,项数少,灾难性抵消罕见,误差远小于蒙特卡洛方差,不需要这样处理。
不同观点并列
- 6.8.4 正文 vs 第 6 章最后一道习题:正文说"变换顶点到射线坐标系引入的舍入误差不影响水密性,因为所有三角形用的是同一个变换";最后一道习题则指出平移和切变的舍入误差"破坏了当前实现的水密性",需要在三角形包围盒中计入,并引用 Woop 等 (2013) 3.3 节给出修正。两种说法放在一起看:边函数符号检验本身是水密的,但顶点变换误差可能让交点落在 BVH 包围盒之外而被提前剔除。
- "机器 epsilon"的两种定义:PBRT 6.8.1 脚注说 C/C++ 标准把机器 epsilon 定义为 1 之上一个 ulp(float 为 ),"是数值分析通常用法的两倍",并把 称为机器 epsilon。但书中误差分析所依据的 Higham《Accuracy and Stability of Numerical Algorithms》(2002)恰恰把 1 到下一个浮点数的距离 叫机器 epsilon,把最近舍入的最大相对误差 叫单位舍入误差 (unit roundoff) ;两种叫法在数值分析文献中都有人用(Wikipedia "Machine epsilon" 的 formal/mainstream 两种定义;pbrt-v4 issue #194:https://github.com/mmp/pbrt-v4/issues/194 )。本页的 沿用 PBRT 的记号,对照 Higham 时应读作 ;所有误差界本身不受影响。
- 固定 epsilon 与保守偏移:实时光线追踪(见 硬件光线追踪与路径追踪器)若用固定的 或固定比例偏移,就是上文"传统做法"的取舍;PBRT 的保守偏移换来正确性,但要付出上文"代价与比较"所述的遍历代价。
取舍
- 保守误差界保证"不自相交",但偏移太小会让遍历变慢,约 20%。
- 区间算术实现简单,但对高频操作(点变换)太慢、界太宽;高频路径值得手工推导。
- 只有交点位置需要这样认真处理;导数、纹理坐标的误差影响很小。
出处
- PBRT 4e source excerpt: chapter 06 (Shapes)
- Pharr, Jakob, Humphreys《Physically Based Rendering: From Theory to Implementation》第 4 版(MIT Press, 2023)第 6 章 6.8 节,pbr-book.org/4ed/Shapes
相关页面
游戏数学数值表示与浮点数Numeric Representation & Floating Point游戏引擎里到处是数值,所以要清楚它们在机器中如何存储:二进制和十六进制、补码整数、定点数、IEEE-754 浮点数(量级与精度此消彼长、次正规数、机器 epsilon、ULP),以及多字节值的大小端问题和安全的类型双关 (type punning) 方法。书中一个直观的例子是:用 32 位浮点数记录以秒为单位的游戏时钟,大约 12.14 天后,加 1/30 秒就不再改变它的值。游戏数学光线求交测试Ray Intersection Tests光线求交用于拾取、光线追踪、地面高度查询等。本页给出四类经典测试:光线-球(代数解与带早期拒绝的几何优化解)、光线-盒(平板法与光线斜率法)、光线-三角形(Möller-Trumbore,直接从顶点求重心坐标与距离)、光线-多边形(先求平面交点,再投影到二维做交叉数测试)。共同思路是先做便宜的拒绝测试、推迟除法与开方、必要时降维。图形学随机光线追踪与路径追踪Stochastic Ray Tracing & Path Tracing光线追踪用投射光线同时解决可见性问题和光照问题。GEA 从最简单的"眼睛光线 + 着色方程"讲起,逐步加入阴影光线、透射光线、用蒙特卡洛估计渲染方程的随机光线追踪、递归间接光照,再到每次只走一条路径的路径追踪、双向路径追踪和 Metropolis 光传输,最后讨论降噪与光线投射效率(GEA4 卷 II 12.6.3–12.6.5)。游戏开发 · UE5硬件光线追踪与路径追踪器Hardware Ray Tracing & Path TracerUE5 的硬件光线追踪 (HWRT) 大部分功能都集成在 Lumen 里;也有光追阴影等独立功能。Lumen 在显卡、RHI 和操作系统支持时使用 HWRT,否则回退到软件光追;反射光线可以用表面缓存(快)或命中点光照(质量高)来着色;实例超过 10 万时,HWRT 的场景更新开销很大。路径追踪器 (Path Tracer) 是渐进式、硬件加速的无偏渲染模式,用作 ground truth 参考和影视级最终输出,与 Sequencer/Movie Render Queue 集成。