中EN
概念页

浮点误差与鲁棒光线求交

Floating-Point Error & Robust Ray Intersection

光线追踪中,交点的浮点误差会让次级光线(阴影、反射)从表面"下方"出发、错误地再次击中自身(自相交,俗称 shadow acne),或因偏移过大漏掉近处遮挡(漂浮的阴影)。PBRT 第 4 版 6.8 节不靠经验 "ray epsilon",而是用前向误差分析为每个交点算出保守的误差盒,再沿法线把光线原点推出误差盒,做到可证明不自相交、偏移又极小。

问题与传统做法(6.8 引言)

常见做法是给新光线设最小参数 tmint_{min}(固定 epsilon)。但若交点在表面下方而新光线很斜,错误的再相交可能发生在离原点相当远的地方,所以 tmint_{min} 必须取得很大;取大了又会漏掉附近的真实相交,丢失阴影和反射细节(PBRT 4e 图 6.38、6.39)。

浮点误差的基本工具(6.8.1)

浮点格式本身见 数值表示与浮点数;这里只列分析误差需要的结论:

  • IEEE 754 保证 +,−,×,÷,+,-,\times,\div,\sqrt{} 和 FMA 的结果等于精确结果舍入到最近的浮点数,所以 a⊕b∈(a+b)(1±ϵm)a\oplus b\in(a+b)(1\pm\epsilon_m)。32 位浮点在 [2e,2e+1)[2^e,2^{e+1}) 内间距为 2e−232^{e-23},半个间距给出机器 epsilon ϵm=2−24≈5.96×10−8\epsilon_m=2^{-24}\approx5.96\times10^{-8}(本页验算)。乘除 2 的幂、x⊖xx\ominus x、1⊗x1\otimes x 等都是精确的。
  • 误差连乘 (1±ϵm)n(1\pm\epsilon_m)^n 用 Higham 的 γn=nϵm1−nϵm\gamma_n=\frac{n\epsilon_m}{1-n\epsilon_m} 界住(式 6.23),且商 (1±ϵm)m(1±ϵm)n\frac{(1\pm\epsilon_m)^m}{(1\pm\epsilon_m)^n} 以 γm+n\gamma_{m+n} 为界,不能约掉。
  • 例:((a⊕b)⊕c)⊕d((a\oplus b)\oplus c)\oplus d 的绝对误差界为 ∣a+b∣γ3+∣c∣γ2+∣d∣γ1|a+b|\gamma_3+|c|\gamma_2+|d|\gamma_1;(a⊕b)⊕(c⊕d)(a\oplus b)\oplus(c\oplus d) 则约为 3ϵm(∣a+b∣+∣c+d∣)3\epsilon_m(|a+b|+|c+d|),所以大量求和时从小到大排序更准。
  • 乘法相对误差约 (i+j+1)/2(i+j+1)/2 ulp,很温和;同号加法也温和;异号相加(或同号相减)在 a≈−ba\approx-b 时相对误差 ≈2∣a∣γ∣a+b∣\approx\frac{2|a|\gamma}{|a+b|},即灾难性抵消。
  • 两种做法:手工推导的前向误差分析(便宜、界更紧),以及让程序在运行时用区间类 Interval 跟踪误差的运行时误差分析(方便,但对点变换来说界宽 3–6 倍、慢约 6 倍)。
  • 小工具:NextFloatUp/Down() 直接对位模式加减 1(正无穷不变,−0-0 先跳到 +0+0);按位重解释必须用 std::bit_cast(C++20,pbrt 自带 C++17 实现),指针强转和 union 读另一成员都是未定义行为。

各环节的误差处理

环节问题PBRT 的做法
光线-包围盒(6.8.2)t=(x−ox)⊗(1⊘dx)t=(x-o_x)\otimes(1\oslash d_x) 误差 $\gamma_3t
球/圆柱判别式(6.8.3)球离射线原点远时 b2≈4acb^2\approx4ac,灾难性抵消,书中把单位球放在 400 单位外正交观察时边缘会漏交改写为 b2−4ac=4a(r2−∥o−b2ad∥2)b^2-4ac=4a\big(r^2-\|\mathbf o-\tfrac{b}{2a}\mathbf d\|^2\big),消去误差最大的 cc,再用 x2−y2=(x+y)(x−y)x^2-y^2=(x+y)(x-y);改进后球可移到约 7,500 单位外仍正确。直接用 DifferenceOfProducts() 不行,因为 a,b,ca,b,c 自身已有误差
三角形(6.8.4)共享边上的漏交边函数 (a⊗b)⊖(c⊗d)(a\otimes b)\ominus(c\otimes d) 的符号在浮点下总是正确;为 0 时用双精度重算
交点位置(6.8.5)o+td\mathbf o+t\mathbf d 的误差 $\gamma_1o_x
变换(6.8.5)物体空间求交再变回来精确点误差 $\gamma_3(
新光线原点(6.8.6)原点要在表面正确一侧沿法线偏移 $d=
交点在原点后面(6.8.7)舍入让真实 t<0t<0 的交点算成 t>0t>0平板测试的 tt 符号天然正确;二次曲面用区间判断;三角形推导 δz,δx,δy,δe,δt\delta_z,\delta_x,\delta_y,\delta_e,\delta_t,要求 ∑eizi>δt\sum e_iz_i>\delta_t(场景尺度 ±10 时约 10−710^{-7});双线性面片用基于输入量级的 epsilon

阴影光线到面光源的问题没有解决:pbrt 把阴影光线的 tmaxt_{max} 设为略小于 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 为 2−232^{-23}),"是数值分析通常用法的两倍",并把 2−242^{-24} 称为机器 epsilon。但书中误差分析所依据的 Higham《Accuracy and Stability of Numerical Algorithms》(2002)恰恰把 1 到下一个浮点数的距离 2−232^{-23} 叫机器 epsilon,把最近舍入的最大相对误差 2−242^{-24} 叫单位舍入误差 (unit roundoff) uu;两种叫法在数值分析文献中都有人用(Wikipedia "Machine epsilon" 的 formal/mainstream 两种定义;pbrt-v4 issue #194:https://github.com/mmp/pbrt-v4/issues/194 )。本页的 ϵm=2−24\epsilon_m=2^{-24} 沿用 PBRT 的记号,对照 Higham 时应读作 uu;所有误差界本身不受影响。
  • 固定 epsilon 与保守偏移:实时光线追踪(见 硬件光线追踪与路径追踪器)若用固定的 tmint_{min} 或固定比例偏移,就是上文"传统做法"的取舍;PBRT 的保守偏移换来正确性,但要付出上文"代价与比较"所述的遍历代价。

取舍

  • 保守误差界保证"不自相交",但偏移太小会让遍历变慢,约 20%。
  • 区间算术实现简单,但对高频操作(点变换)太慢、界太宽;高频路径值得手工推导。
  • 只有交点位置需要这样认真处理;导数、纹理坐标的误差影响很小。
  1. PBRT 4e source excerpt: chapter 06 (Shapes)
  2. 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 集成。

输入关键词开始搜索

滚轮或双指缩放 · 拖动平移 · 双击放大 / 还原