"Algorithms leveraging ReSTIR-style spatiotemporal reuse have recently proliferated, hugely increasing effective sample count for light transport in real-time ray and path tracers. Many papers have explored novel theoretical improvements, but algorithmic improvements and engineering insights toward optimal implementation have largely been neglected. We demonstrate enhancements to ReSTIR PT that make it 2–3× faster, decrease both visual and numerical error, and improve its robustness, making it closer to production-ready. We halve the spatial reuse cost by reciprocal neighbor selection, robustify shift mappings with new footprint-based reconnection criteria, and reduce spatiotemporal correlation with duplication maps. We further improve both performance and quality by extensive optimization, unifying direct and global illumination into the same reservoirs, and utilizing existing techniques for color noise and disocclusion noise reduction."
- 这篇的定位很特别:它并不试图提出新的重采样理论,只把一套已有理论做成能用的实现。原文自己点了这个空白:ReSTIR 系的方法「最近大量涌现」,理论改进被反复研究,但朝向最优实现的算法改进与工程经验被普遍忽略。
- 三件基建,对应三类毛病:空间复用里两趟 shift 的重复劳动(改法:邻域配对,省一半搬运);重连阈值要靠人按场景调、且在光泽材质上不稳(改法:双 footprint 阈值,把几何推导收成一个常数);复用带来的相关性斑块(改法:用 duplication map 测「有多像」,在像的地方自适应压低时间置信)。
- 一笔收益:四场景平均从 35.73 ms 降到 13.04 ms(2.74×);把为质量付出的三项加回去是 15.53 ms,仍比基线快 2.30×(质量代价 +19%)。首图那个 Spaceship 场景是 37.1 ms / FLIP 0.321 → 12.6 ms / FLIP 0.263,慢的地方变快,错的地方变准。
- 一笔明账:自适应降 cCap 会破坏 MIS 的权重归一,必然引入偏差。原文把这件事摊开了:困难场景 Kitchen 上平均绝对相对偏差 3.25%,光泽面偏差更大。这是用偏差换相关性,不是白拿。
112.6 毫秒对 37.1 毫秒
12.6 毫秒对 37.1 毫秒
ReSTIR 路径追踪(ReSTIR PT)在 2022 年提出时,解决的是一件很漂亮的事:把路径样本在像素之间、帧之间搬来搬去,用极低的代价换到几十上百倍的等效采样数。但它的原型有几个现实问题。原文把话说得很直:原型有很高的计算与内存开销,即使在高端 GPU 上也很慢,最初在 RTX 3090 上是每帧 40 到 80 毫秒。
这篇论文要处理的,就是这类「理论很好、实现还不行」的账。首图把它的成绩摆在一起了。
原文列的五个贡献可以归成两组。第一组是真正的算法改进:把空间复用的成本砍一半(第 3 章)、用基于 footprint 的新阈值替换原来的手调阈值(第 6、7 章)、用 duplication map 压相关性(第 8 章)。第二组是工程与复用既有技术:把直接光与全局光的 ReSTIR 统一到同一组 reservoir 里,以及一堆降低分歧、压低颜色噪声与去遮蔽噪声的优化(第 9 章)。
这个分组本身要记一笔,因为它解释了这篇论文为什么能被评成 Best Paper:它没有假装自己提出了新理论,而是把「理论到产品之间那段被忽略的路」认真走了一遍,并且把每一段的收益单独列了出来。 第 10 章那张表就是这段路的路单。
在往下走之前,有件事要先摆正:这是一篇关于「实现」的论文,所以它的每一个结论都挂在具体的测量口径上。 换一块 GPU、换一个分辨率、换一套初始采样预算,Table 1 的那些毫秒数都会变。在这类论文里,这一点反而要当成价值看——它把口径写清楚了,你才知道哪些结论可以搬走、哪些只是这一套配置下的读数。下面这些数字在引用时都要连口径一起引。
先交代两个口径,后面所有数字都挂在这上面。硬件是 RTX 5880 Ada 加 Threadripper PRO 3975WX,框架是 Falcor,所有图像都是 1920×1080;初始采样是 1 spp(每像素一棵路径树),然后靠时空复用把等效采样数堆起来。误差指标用 HDR FLIP,原文给的理由是它「与切换对比图像时的感知差异高度一致」——这是一个有意的选择,第 11 章会看到它在这个场景下比 PSNR 更好用。
2为什么「复用」会变成「复用得太像」
要理解这篇论文的三刀切在哪,得先看清「相关性」这件事是从哪来的。
原文把样本相关性的来源归结为两条:一是初始采样产生的低概率、高能量的萤火虫;二是不完美的 shift 映射,它会人为地把样本搬成高能量萤火虫。 这两条性质不同:第一条是采样本身的问题,任何蒙特卡洛渲染器都有;第二条是复用机制自己制造的——你把一个像素的样本搬到邻居那里,如果映射不够准,搬过去的样本就和它在新位置的真实分布不匹配。
麻烦在于,时空复用会把局部问题变成区域问题。原文的描述是:这些萤火虫会通过时空复用扩散到邻近像素,形成相关性斑块(correlation blobs),形状可能是圆盘也可能是条纹,有时占据大量像素、并持续很多帧。原文还补了一句:参数选得不好会加剧这个问题,比如空间复用半径取得太小。
「半径太小反而更糟」这一条要停一下,因为它反直觉。直觉上,复用半径越小,搬来的样本离得越近、越应该像。但问题恰恰在「像」上:半径小意味着同一批候选样本在很小的区域里被反复复制,于是这片区域里的所有像素拿着高度相似的样本,任何一颗萤火虫都会被这片区域完整地继承下来。半径大一些反而是把样本摊薄,相关性被平均掉一部分。
最后一条后果最致命,也最容易被忽略:相关性伪影会让降噪变得困难,因为降噪器会把伪影当成信号。 现代实时渲染管线里降噪是必经环节,而降噪器的工作假设是「看到的亮斑要么是信号、要么是独立噪声」。相关性斑块两种都不是:它长得像结构(所以被当作信号保留),却又不是真实结构。这一步把「画面不好看」升级成了「后处理链失效」,也是这篇论文要专门花一整节处理相关性的原因。
这里还有一个容易被忽略的层次问题:相关性并不只是「噪声大一点」,它是「误差的结构错了」。 普通噪声是零均值的颗粒,样本数一多就自己收敛掉;而相关性斑块是有结构的、系统性的偏差,它不会随着时间自动消失,反而会被复用链路持续搬运、放大、并要求降噪器把它保留下来。用一句话区分:噪声是「看不清」,相关性是「看错了」。 这也决定了它的解法必然不同于降噪——降噪治不了它,甚至会让它更顽固,必须在复用机制内部处理。
先把复用所用的这套重采样理论写清楚,后面三刀都长在它上面。ReSTIR 的地基是广义重采样重要性采样(GRIS):候选样本可能有不同的分布、来自不同的定义域、甚至是相关的,它们通过双射映射被搬到目标定义域,参与加权的式子是这样:
这个式子里有四项,一项一个角色:p̂(Yi) 是目标分布(我们想让样本落在哪)、W_Xi 是无偏贡献权重(来自上一轮重采样的「这个样本值多少」)、|∂Ti/∂Xi| 是 shift 映射的雅可比行列式(搬过去的坐标变换怎么改变密度)、mi 是重采样的 MIS 权重(负责把多个来源的覆盖范围归一化)。原文还给了收敛条件:当加权和 Σwi 的方差趋近于 0 时,重采样输出趋近目标分布。
这四项里,第 3 项就是本文后面反复动的地方。 第 3 章要把计算它的次数砍一半,第 6、7 章要改进它的质量,第 8 章要处理它不完美时留下的痕迹。记住这一点,后面三刀就不再是三件不相干的事。
3第一刀:把两趟搬运合成一趟
先看一笔很具体的浪费。
在 ReSTIR 的空间复用里,当前像素要从邻居取样本。但取样本这件事不是单程的:邻居的路径要被搬到当前像素来,同时当前像素的路径也要被搬到邻居那里去,因为计算 MIS 权重需要知道「如果反过来复用会怎样」。原文的说明是:即使使用了高效的成对 MIS,所有空间邻居都要求两次 shift,这让工作量翻倍。
图 3-1 把这两种情形画在一起了。
这就是第一刀的全部洞见,一句话能说完:你去邻居家取东西,邻居还得来你家评估一次,既然两趟都必须跑,那就顺路一趟办完。
落实方式是把像素成对绑起来。既然 A 从 B 取和 B 从 A 取用的是同一对映射,那就预先算一张复用纹理(reuse texture),让每个像素知道自己「绑定的伙伴」是谁。原文的说法是:A 存一份指向 B 的坐标偏移,B 存一份指向 A 的偏移;要支持从多个邻居复用,就准备多张互相独立的纹理。
收益是省掉一半的搬运。但原文也如实说了没省满:配对空间复用并没有完全把成本砍半,因为空间复用被拆成了两趟——一趟预处理把每条路径搬到它配对的所有邻居那里,第二趟才做重采样。这个「拆成两趟」的开销,在第 10 章的表里能看到具体数字(配对那一步自身是 6.99 → 4.11 毫秒)。
这里先说清这笔收益的性质,因为它容易被读成「省了一半的算力」,实际上不是。省掉的那一趟并没有消失,它只是不需要再重复了。 原来的流程里,A 到 B 的映射与 B 到 A 的映射必须都算(一个用于取值、一个用于 MIS 评估),配对做的事只是把这两次计算的结果互相共享。所以收益不来自近似、不来自少算一项,而来自「同一份计算结果被两个像素共用」。这类收益是无损的,这也是它值得被放在贡献列表的最前面。
先把这一步的理论依据写出来,它和第 6、7 章共用同一个式子。混合 shift 在主采样空间(PSS)里的雅可比行列式是:
这个式子说的是「从 yk−1 重连到 xk 时,路径密度怎么变」。如果压根不发生重连,这个行列式等于 1。它等于 1 的那些位置,就是 shift 映射最理想的位置——搬过去之后样本的密度分布没变,复用不引入额外误差。第 6、7 章要做的事,就是从几何上判断「哪里近似等于 1」,而不是靠人设一个阈值猜。
4配对纹理怎么造
「让每个像素绑定一个伙伴」听起来简单,做起来有一个不平凡的约束:这些配对的坐标偏移必须服从指定的距离分布(否则复用半径就不受控),而且配对是相互的(A 绑 B,B 必须绑 A)。原文坦白了走过的弯路:这个问题带全局约束,他们试过基于优化的做法,结论是又慢又不可靠。
他们的解法很巧:不去解一个全局约束问题,而是洗牌。 先按距离填出一张「每个像素一个编号」的初始纹理,再用随机的 2×2 置换块去洗它,最后把编号相同的像素两两配对。图 4-1 是这个过程的两个状态。
为什么非要用「随机置换」而不是直接按高斯分布撒点?这里有一个约束常常被忽略:配对必须是双向的、并且是一一对应的。 如果只是让每个像素随机找一个高斯距离上的伙伴,那必然出现「A 选了 B,但 B 选了 C」的情况——配对关系不对称,纹理也就不可逆(图 9-1 那个「交换两次复原」的性质会立刻失效)。置换天然满足一一对应:它只是把编号的位置重新排列了一遍,编号本身没变,所以共享同一编号的两个像素永远互相指向对方。
现在把参数讲清。目标是让配对偏移的标准差等于 σ,原文的约束是 σ ≥ 0.8 像素(这是一次置换迭代能给出的最小值,脚注里写明了)。纹理尺寸取偶数、例如 254×254,理由在脚注里:256×256 会产生 ±128 这样的坐标差,那需要 16 位通道才能表示。 这是一个实现约束,不是审美选择。
置换次数由原文给的拟合式决定:
后面那几项负幂是给小 σ 做的拟合修正(原文原话是 function fit correction for small σ),当 σ 不小的时候可以忽略。这个式子背后的推理要跟一遍:
所以「洗 n_σ 次」这个数是从目标标准差反解出来的,并非随手取的。洗完之后还要处理两个工程细节:链接可能跨越纹理边界,于是作者做了一次折返处理:
这样处理之后纹理可平铺;最后把 x 与 y 两个方向的偏移打包成一张 16 位亮度纹理。
先说清「找到伙伴」这一步的数据结构。原文的写法是构造一张尺寸为 N/2 × 2 的表(N 是复用纹理的像素数),每个编号占两行槽位:
最后是「怎么找到伙伴」。这一步在 CUDA 上有一个漂亮的写法:构造一张 N/2 × 2 的索引表,每个像素先把自己的位置写进 (自己的编号, 0) 槽位——这是一个有数据竞争的并行写,所以只有一半像素成功;然后那些没写进 0 列的像素,把自己的位置写进 (自己的编号, 1) 槽位。两次写入之后,每个像素都能从索引表里查到伙伴的位置。用一次「允许失败」的写来省掉一轮同步,是这类 GPU 代码里很典型的手法。
5为什么不能每帧重生成
配对纹理有一个性质决定了它的使用方式:它是自逆的。A 链到 B,B 链到 A。而「自逆」加上「复用需要空间上的多样性」,意味着同一张纹理不能连续两帧照用——否则同一批像素会一直在互相交换样本,形成固定的对话关系,相关性反而更强。
最直接的想法是每帧重新生成一张。但生成要花算力,而这篇论文整个目标就是省算力。作者的替代方案是对已有纹理做随机变换:每帧随机地翻转、镜像、转置、偏移每张纹理。原文的措辞是:经验上,这完全解决了问题。
还要解决第二个问题:如果只用一张纹理,配对的形状会有固定的统计特征,可能在画面上留下可见的图案。原文的做法是同时准备多张纹理,而且给每张取不同的尺寸,例如三个邻居分别用 254、230、210。尺寸不同,重复周期就不同,叠加起来才不会形成规则的拍频图案。
这里顺便把「和既有做法的差别」讲清,因为分区里已经读过 ReSTIR 家族的几篇。原文点名对比的是 Bekaert 等 2002 年的做法:把 16×16 的像素块切成 16 个一组的 N-rooks 图案,在组内做全员互相复用。 那个做法同样省掉了 MIS 权重的额外工作,但在低采样数下会产生结构性伪影。本文避免结构性的方式是不分块:把多张尺寸不同、经过高斯置换的大纹理叠起来,每个像素跟随的是一套随机的、没有块边界的复用图案。 原文还留了一句适用范围:这套复用纹理同样可以用在经典的路径复用里,不绑定 ReSTIR PT。
6第二刀:把「人来调阈值」换成「从几何算阈值」
第二刀处理的是重连阈值。
ReSTIR PT 的混合 shift 要选一个「重连顶点」xk:在它之前沿用原路径的顶点,在它那里把路径接到新位置。选哪个顶点当重连点,由一个判断决定。原始做法用了两个阈值:一个距离阈值 ‖xk − xk−1‖ ≥ d_min,用来禁止过短的重连(也就是禁止在角落附近重连);一个粗糙度阈值 min(αxk−1, αxk) ≥ α_min,用来禁止在高光泽表面上连接。
原文对这两个阈值的不满有两层。第一层是它们互相纠缠:合适的重连距离与粗糙度水平彼此依赖,改一个就得改另一个。第二层更麻烦:它们经常需要按场景逐一调整(often require scene-specific tuning)。对一篇要走向产品的论文来说,「每个场景都要人调」本身就是缺陷。
替换方案是双重的光线 footprint 阈值加一个新的单顶点粗糙度阈值。原文给这套新约束列了三条特性,要逐条记:在光泽材质存在时更稳、不需要按场景调参、而且能更早重连——最后这一条直接换成成本,因为重连越早、要重放的路径段越短、越便宜。
那「从几何算阈值」是什么意思?原文的出发点是一个理想条件:好的 shift 映射应该让雅可比行列式近似等于 1。
也就是说,搬过去的样本在目标分布下应该还是同样的密度。原文把注意力收在这个行列式上(假设两个像素的目标分布本身接近),而行列式只受「选了哪个重连顶点」影响。于是问题变成:怎样从几何上判断「这个重连点的行列式接不接近 1」?
答案是把行列式拆成两个比值的乘积:
这两个比值各自有明确的几何含义,第 7 章会分别给它们配一个可计算的判据。这里先记结论:两个判据共用同一个常数 c,原作者实测 c = 0.02 在多种场景下都工作良好。 把一堆几何推导收成一个旋钮,是这套改法能取代手调阈值的关键。
还有一层值得放在这里的方法学观察:新判据取代的不只是两个阈值,而是「调参」这个动作本身。 原来的做法要求使用者理解「这个场景的重连距离该取多少、粗糙度阈值该取多少」,这两个量还互相纠缠;新判据要求使用者理解的只剩一个 c,而且它的语义是单调的(越大越保守)。把一个需要领域知识的多参数问题,降成一个单调的单参数问题,是这类改进能不能被别人的引擎采纳的关键。 论文给出的 0.02 只是在作者测过的场景里工作良好,但即使你的场景需要另取一个值,你也不需要重新推导一遍。
顺带说清「c 变大变小意味着什么」,这是使用时唯一需要理解的调参语义:c 越大,重连越保守,也就是更倾向于推迟重连。 因为它放宽了容差、提高了判据的门槛。原文还保留了一个单顶点粗糙度阈值(用在 xk−1 上),以及在漫反射或自发光顶点上跳过逆 footprint 测试——第 12 章会把这两个例外列进边界。
7阈值是怎么推出来的
这一章跟一遍两个判据的推导思路,不追全部细节(原文把完整推导放在补充材料里),目的只是让你知道这两个阈值为什么能从「摊开多大」这样一个几何量推出来。
先看第一个比值。它比较的是「从 yk−1 重连」与「从 xk−1 重连」两种情况下,xk 这一点上的面积密度变化。原文的分析路径是这样的:假设随机重放保持局部面积密度不变,那么面积密度的变化就取决于xk 位置被挪动了多少,也就是 Δxk = yk − xk。
接下来是一个关键假设:这个位移的大小,被「主光线的 footprint」限制在一个常数倍以内。 这里的主光线 footprint 借自 Müller 等 2021 的工作,它度量的是像素在场景里覆盖的面积。基于这个界,原文得到了一个充分条件:只要
这里的 R^pri 就是主光线的 footprint,c₁ 与 c 是常数(实现上把 c₁²/c² 收成式子 5 里那一个 c)。这个条件的物理含义是:在 xk 附近,光线覆盖的面积必须比「主光线在这一点摊开的面积」大足够多。 原文对这一条的注释是:它能避免在由光泽 BSDF 或几何奇点造成的密度峰附近重连。
把这句话用图 7-1 演一遍更容易懂。
但第一个判据只管住了面积密度,管不住出射方向的概率密度。原文指出了这个缺口:改动出射方向 −ωk−1 会改变 BSDF 采样的 PDF p^xk(ωk),而这个变化在低粗糙度的光泽材质上可能非常大。于是有了第二个判据——逆 footprint:
它的物理含义更漂亮:在近似认为光泽材质的 BSDF PDF 满足互易性的前提下,这个量可以理解为「一条反向追踪的光线(假想从光源出发)每个样本覆盖的面积」。 也就是说,它把同一个判据从「正着看」翻了「反着看」:正着看是「这个点被像素覆盖多大」,反着看是「这个点被光线覆盖多大」。原文说这两项共用同一个 c,并且这样就能安全地重连到远处的光泽表面,而不必在 xk 上强加粗糙度阈值。
把这些收口成一句话:原来的两个手调阈值之所以难调,是因为它们试图直接描述「什么样的重连点算好」;新的判据改成描述「重连造成的密度变化有多大」,而后者可以从 footprint 这个几何量上界住。 判据的性质从「经验阈值」变成了「有推导的充分条件」,于是 c 可以跨场景通用。
最后补一个必须处理的例外。重连到环境光时,Δxk 是无界的,角度密度也可能突变,footprint 的推导前提不成立。原文的兜底就是保留在 xk−1 上的那个单顶点粗糙度阈值。这也是为什么它没有被完全去掉,而是被降级成了一个兜底条款。
8第三刀:测到「太像」就降时间置信
第三刀处理的是相关性本身,做法比前两刀朴素得多,也更值得学。
原文的动机推理只有一句:我们给时间样本多大的权重,直接决定相关性能有多强。 高度信任时间复用,就等于给萤火虫更多在空间上扩散的机会、也让它们更持久地留在画面里。所以「相关性」这个量不必去建模,只要去测——测出来太高,就把时间置信度压下去。
测法就是数数。原文的定义是:统计一个空间邻域里有多少像素和我共享同一个样本(所谓共享,指的是这些样本是同一个初始候选的平移副本)。识别的办法很直接:比对那些为了随机重放而已经存下来的随机种子。
三步实现:
- 每帧结束后算一张样本重复图。 每个像素统计周围 17×17 区域内有多少个 reservoir 与自己共享随机种子,这个计数除以 288 得到重复分数 D ∈ [0, 1]。
- 做时间重采样时,查当前像素回溯到上一帧的那个位置的 D 值。
- 用 D 调整 cCap:
其中 cCap 默认值是 20(沿用 Lin 等 2022 的设定)。α 控制的是下降曲线的形状:α = 1 是线性下降,α 越接近 0 则随着 D 上升下降得越快。作者实测取 0.1,也就是说一旦发现明显的重复,置信度就快速压到底。
图 8-1 是这个机制在一段很难的画面上的实测,连着偏差一起给了。
为什么会有偏差? 这一点原文没有绕开:因为这种做法是按具体样本调整置信权重的,它破坏了 MIS 权重的 partition of unity(权重之和为 1 这个性质),于是引入了小偏差。原文对这件事的定性很干脆:这个方案是在用偏差换相关性。
它还把这种偏差的范围界定了:偏差只发生在被修改 cCap 的那些相关区域。 这一条很重要——它意味着画面的大部分区域保持无偏,代价被集中在那片本来就要出问题的地方。第 11 章的收敛曲线会从另一个角度证实这一点。
再看一眼「不去相关」是什么样子,才能理解这一步的收益为什么值 3.25%。
9顺手改掉的一堆工程问题
前三刀之外,第 6 节还有一串「不是新算法但很值钱」的改动。原文把它们归成实现改进,这里按它的五个小节讲。
一是把直接光与全局光统一到同一组 reservoir。 实时渲染器通常把直接光与间接光分开算,而且间接光常被更激进地近似。原文指出,有了 ReSTIR 之后这个妥协不必要了:与其像 Lin 等 2022 那样跑两遍独立的 ReSTIR,不如合并成一组 reservoir。具体做法是在生成路径树时从 x₁ 额外投一条 NEE 射线,让初始重采样有机会从树里选出一条更短的、长度 d = 2 的直接光路径。原文说这样一来,选出的路径就是从完整路径空间里采样出来的。
这个改动省掉了独立两遍 pass 的成本与存储。但原文用了一个词:有点意外地(somewhat surprisingly),它还提升了质量——因为直接光现在也能享受 ReSTIR PT 内置的 shift 映射,在光泽高光上尤其明显。对光源很多的场景,它可选地在 x₁ 处生成 NEE 样本时先做一轮 RIS,并且沿用了 ReSTIR DI 的口径:目标函数里不含可见性,只对选中的光源做可见性测试。光照取样用 Wyman 与 Panteleev 2021 的预采样光照贴片方案来提高缓存一致性:每帧预计算 128 张片子、每张 1024 个光源,每个 8×8 的屏幕块抽一张片子来生成各次弹射的候选。 候选数量随弹射深度衰减:
这是一条典型的预算分配:离相机近的地方光路更重要,样本给得多;越深的弹射越接近环境光,给一个就够。
二是降分歧。 原文对问题的描述是:蒙特卡洛路径追踪本身就有大量 GPU 分歧(相邻的路径走过完全不同的几何与材质),而 ReSTIR PT 因为额外的控制流与中间数据(比如 reservoir)进一步加剧了分歧。它做了四件事:把大部分分支换成条件移动并简化计算(结果等价);把 reservoir 的存储从 88 字节压到 64 字节(去掉无用字段 + 对部分量做有损压缩);用流压缩剔除不需要随机重放的「像素-邻居对」(很多场景里只有少数对需要重放,但 warp 级执行会逼着所有线程一起等);以及强制 NEE 光照重连——随机重放时,终止在 NEE 采样顶点的路径要做昂贵的光照采样,而重放用的随机数通常还会选中同一盏灯,于是干脆在找不到更早的重连点时强制在这类顶点重连,把光照采样从随机重放里彻底删掉。
这三项里前两项治的是「路径多样性」,第三项治的是「执行不整齐」。 条件移动与流压缩解决的是指令发散(同一个 warp 里的线程走了不同的分支,于是都被拖慢),强制 NEE 重连解决的是数据发散(少数线程要做昂贵的光照采样,其余线程只能等)。这个区分不是名词游戏:能并行的活变多叫利用率不足,能一起跑的活被迫分开跑叫发散,两者的修法完全不同——前者要减少工作量,后者要减少分支。原文用 NSight 的三项指标把改善量化了,第 11 章会看到。
三是俄罗斯轮盘。 初始重采样常是最贵的一步,因为路径又长又分歧。本文在初始采样时施加轮盘以缩短平均路径长度,但在随机重放里禁用轮盘,免得在复用过程中把有效路径杀掉。原文说这样做实际上把轮盘维度从路径参数化里移除了,代之以初始采样处的一个外部轮盘。代价是初始样本的噪声略微上升,但时空复用会在最终结果里把这点影响基本压平。
四是颜色噪声。 这一条解释了一个以前不太被明说的问题:ReSTIR 天然有颜色噪声,因为重采样作用在标量目标函数 p̂ 上,而被积函数 F(y) 是 RGB 的。GRIS 因此主要在亮度上做重要性采样,色度没有被好好采样。修法是把重采样权重改成向量:
与公式 2-1 相比,唯一的差别是多了那个加粗的 F(Yi):标量权重负责驱动重采样,向量权重负责着色。原文强调在 ReSTIR PT 里这个改进几乎不花额外成本,因为 p̂ = |F|,F(Yi) 在空间复用阶段本来就已经算过了。这么做等于把重采样与着色解耦:标量权重继续驱动后续重采样,向量权重只用于着色,而空间邻居身上的色度噪声通常是不相关的,于是被自然平均掉。
五是去遮蔽噪声。 去遮蔽(disocclusion)会让 ReSTIR 出严重噪声,因为新露出的表面没有任何时间历史。修法是对偶运动矢量(借自 Zeng 等 2021):用一条替代的运动矢量重新投影像素,那条矢量假设遮挡面与被露出面之间有相对一致的运动会持续下去。原文把它直接应用到 ReSTIR 的时间重采样上,实测去遮蔽噪声大幅下降。这里有一处对「为什么可以直接搬」的解释:以往工作需要存入射辐射场来避免复制粘贴伪影,而在 ReSTIR PT 里这个问题不会出现,因为无偏的路径重采样本身就阻止了图案克隆。
这一节的两个可视化支撑分别是「配对纹理是可逆的」与「σ 与 R 的等价性」。
两张图放在一起看,一边是机制、一边是参数:机制要能逆,参数才谈得上「与原来等价」。
也就是说,——各向同性高斯的标准差为 σ 时,平均样本距离是 σ√(π/2);而均匀圆盘半径为 R 时,平均样本距离是 2R/3。令两者相等,得到 σ = √(8/(9π))·R。 对 ReSTIR 的默认 R = 30,这给出 σ = 16.0。换句话说,这张纹理的复用半径与原来那个 30 像素的随机邻居半径在平均距离上是等价的,第 10、11 章的对比才是在同一个尺度上比的。 来源:ReSTIR PT Enhanced, Fig. 7, p.13:12 · © 2026 作者 · CC BY 4.0 · 原样引用,未修改。
10账一:每一步值多少毫秒
从这一章开始对账。原文的表 1 是四条场景(Veach Ajar、Carousel、Opera House、Bathroom)的平均帧成本与分项成本,每一行在前一行基础上加一项改动,虚线以上是省成本的改动,以下是带来质量收益但增加成本的改动。
| 步骤(括号为原文小节) | 总帧 ↓ | 初始采样 | 时间复用 | 空间复用 | DI 及其他 |
|---|---|---|---|---|---|
| 基线(Lin 等 2022) | 35.73 | 10.59 | 5.30 | 14.79 | 5.05 |
| + 代码微优化(6.2.1) | 32.98 | 10.70 | 4.16 | 13.06 | 5.07 |
| + 强制 NEE 重连(6.2.3) | 29.75 | 11.44 | 3.40 | 9.73 | 5.19 |
| + 重放压缩(6.2.2) | 26.81 | 11.79 | 2.66 | 6.99 | 5.37 |
| + 配对空间复用(3) | 25.02 | 12.56 | 2.80 | 4.11 | 5.55 |
| + 俄罗斯轮盘(6.2.4) | 16.52 | 5.21 | 2.24 | 3.83 | 5.24 |
| + 统一 DI 与 GI(6.1) | 13.04 | 6.47 | 2.14 | 3.43 | 1.00 |
| + 新阈值(4) | 14.51 | 6.68 | 2.92 | 3.60 | 1.31 |
| + 全部改善(5、6.3、6.4) | 15.53 | 6.77 | 3.20 | 3.73 | 1.83 |
复算这张表,有五笔账要单独记:
第一笔账是总账:35.73 到 13.04,2.74 倍。这个数在实时渲染里是量级变化:如果原来 40 到 80 毫秒只够跑十几到二十几帧,13 毫秒意味着能稳稳站在 60 FPS 以上。原文在引言里说的「更接近可产品化」,指的就是这个。
第二笔账要说清「配对省了一半」为什么最后只值 1.70 倍。 空间复用这一列从 14.79 掉到 4.11,看起来是砍掉了七成,但其中大部分功劳要归给前面几步(强制 NEE 重连把它从 13.06 打到 9.73,重放压缩再打到 6.99)。配对本身只负责 6.99 到 4.11 这一段。 而它没能拿到理论上的 2 倍,原因原文交代得很清楚:配对把空间复用拆成了两趟(一趟预处理把路径搬到配对邻居,一趟重采样),多出来的那趟是净开销。这是「省一半搬运」这句话在实现里必然要打的折扣。
第三笔账是最大的一步不在算法里。 俄罗斯轮盘一个人贡献了 −10.29 毫秒,几乎占全部收益的三分之一,而它是一件很老的、教科书级的技术。它之所以在这里值这么多钱,原文给的理由是:初始重采样往往是最贵的一步,因为路径又长又分歧,而轮盘直接缩短平均路径长度。这件事对读者的启示是清楚的:在优化一条渲染管线时,「哪一步最贵」这个问题的答案,往往比「哪个算法最新」更能决定收益。
第四笔账是统一 DI 与 GI 的双重收益。 它在成本上把「DI 及其他」这一列从 5.24 打到 1.00(−81%),因为独立的直接光 pass 与其存储被整个取消;同时它在质量上还有收益(直接光也能用 shift 映射)。一个改动同时省成本、提质量,通常意味着原来的结构里有冗余——这也是原文用「有点意外地」这个词的原因。
在算最后一笔账之前,先看清这张表的排列方式本身在说什么。虚线以上每一行都是在「省钱」,虚线以下每一行都是在「花钱买质量」,而两组的分界线并不是「算法 vs 工程」,而是「成本 vs 质量」。原文特意把虚线画在这里,等于在告诉读者:成本削减与质量改进是两笔独立的账,不要混在一起看总数。 一份能这样拆开报的消融表,比一个漂亮的「总加速比」有用得多——因为它允许别人按自己的预算取舍:如果某条管线上质量已经够用,就只取虚线以上那几步。
第五笔账是质量明码标价。 把新阈值、去相关、颜色噪声、去遮蔽这四项加回去,成本从 13.04 回到 15.53,即 +19%。原文对此的定性是:即使带上这些质量改进,仍然比基线快 2.30 倍。 第 11 章会把「这 19% 买到了什么」从视觉效果与硬件指标两个角度补完。
剩下四张图是这一章的定性对照,都是「在同一个尺度下比」(σ=16.0 与 R=30 等价,见第 9 章)。
上面这一组比的是「配对」本身,接下来这一组比的是「去相关」这个动作与既有方案的差别。
去相关是压住相关性,重连阈值是让映射本身更准,两件事都在治第 2 章说的那个病,但作用点不同。
阈值那一组到此为止,下面的图换一个角度:把作者自己遇到的失败案例摆出来。
失败案例之后是正常情形的对照,它的价值反而在于「差别不大」这件事本身。
11账二:为质量多花的 19% 与硬件侧证据
上一章最后一笔账是「质量要价 19%」。这一章补三件事:这 19% 买到什么、收益有多少来自硬件层面的效率、以及参数 σ 该怎么选。
先看整体质量。 图 11-1 是三个场景上与 Lin 等 2022 的整体对比。
再看收益的硬件侧证据。 这是这篇论文里最有说服力的一段论证。作者用 NSight Graphics 对 Opera House 场景做了 profile,得到三组指标:
| 指标 | 基线 | 加 6.2.1–6.2.3 的降分歧优化后 | 再加俄罗斯轮盘 |
|---|---|---|---|
| SM warp 占用率 | 22.4% | 31.1% | 34.9% |
| 每 warp 活跃线程数 | 15.3 | 19.9 | 20.6 |
| warp 延迟(cycles) | 347k | 241k | 82k |
复算这三行的变化:占用率 22.4% → 31.1% 是 +8.7 个百分点(相对提升 39%);活跃线程 15.3 → 19.9 是 +30%;warp 延迟 347k → 241k 是 −31%。再加轮盘之后延迟进一步降到 82k,相对基线是 −76%。
为什么要把这三行单独列出来? 因为它们把「性能收益来自哪里」这个问题答得非常硬。原文特意声明了一件事:这些降分歧的优化「没有改变采样器的行为」。也就是说,前三步的那些收益完全不来自少算一点、近似一点,而是来自把同样的活干得更整齐:占用率上升说明有更多 warp 能被调度(原来是分支太多把 warp 卡住了),活跃线程数上升说明 warp 里的线程不再各自发散,延迟下降是前两者的直接结果。在一篇同时改了算法与实现的论文里,能把两类收益这样分离验证,是很少见的。
第三件事是 σ 怎么选。 图 9-2 已经给出等价关系 σ = √(8/(9π))·R,作者又做了一次扫描来验证:
| 配对纹理 σ | 帧时间 | FLIP ↓ |
|---|---|---|
| 2.7 | 3.72 ms | 0.313 |
| 5.3 | 3.99 ms | 0.289 |
| 10.6 | 3.77 ms | 0.283 |
| 16.0 | 3.79 ms | 0.287 |
复算这张表:σ 从 2.7 增到 10.6 时 FLIP 从 0.313 降到最低点 0.283(−0.030),继续增到 16.0 时回升到 0.287。 也就是说质量在最优点附近是平的,10.6 与 16.0 只差 0.004,而帧时间几乎不受影响(3.77 到 3.79 毫秒)。这说明 σ 不是一个需要精调的参数——只要落在 5 到 16 这个区间,结果都对得上;作者选 16.0 的依据不是它最优,而是它与既有工作的 R = 30 在平均样本距离上等价,这样对比才公平。
最后看收敛。 图 11-2 是收敛曲线,它检验的其实是第 8 章那笔「偏差」的账到底有多大。
12边界与反例
前面十一章讲的是这套方法怎么成立。这一章只讲它在什么条件下不成立、以及哪些数字不能按字面读。十条,每条都指回前面的位置。
一、降 cCap 必然引入偏差,这是明账不是隐患。 它破坏了 MIS 权重的 partition of unity,而且偏差只发生在被修改 cCap 的相关区域。原文实测在困难场景 Kitchen 上平均绝对相对偏差 3.25%,并且逐像素可视化显示光泽表面偏差更大。它的定性是「用偏差换相关性」。把这笔账写在明面上,比宣称「无损」可信得多。
二、σ 有硬下限 0.8 像素。 这是一次置换迭代能给出的最小标准差。也就是说,这套配对机制不支持任意小的复用半径——如果你想用比 0.8 像素更近的邻居,就得换机制。
三、纹理尺寸取 254 而不是 256,是位宽约束。 256×256 会产生 ±128 的坐标差,16 位通道表示不了这个范围(除非用更多位)。这是一条实现约束,改尺寸意味着改数据格式。
四、自逆纹理必须每帧变化。 A 链 B、B 链 A,如果同一张纹理连续使用,同一批像素会一直互相交换样本,形成固定的对话关系,反而加重相关性。作者的解法是随机翻转、镜像、转置、偏移,而不是重新生成。原文的措辞是「经验上完全解决了问题」——注意这是经验结论,不是定理。
五、多张纹理必须取不同尺寸。 例如三个邻居分别用 254、230、210。尺寸相同会让纹理重复本身带来新的周期性伪影,这一点在实现里很容易被忽略。
六、环境光重连是 footprint 阈值的例外。 重连到环境光时 Δxk 无界、角度密度可能突变,footprint 推导的前提不成立,靠第 4.2 节那个单顶点粗糙度阈值兜底。这也是为什么那个「老阈值」没有被完全删掉,而是被降级成兜底条款。
七、漫反射与自发光顶点会跳过逆 footprint 测试。 因为重连不影响这类顶点的角度 PDF。这不是近似,是判据在该情形下自然失效,所以直接跳过。
八、去遮蔽那一条是迁移而非新提出。 对偶运动矢量来自 Zeng 等 2021,本篇做的是把它直接应用到 ReSTIR 的时间重采样。它「不会产生复制粘贴伪影」的理由也很具体:无偏的路径重采样本身就阻止了图案克隆,因此不需要像以往工作那样存入射辐射场。理解这一点才能知道这项收益的前提是无偏性。
九、评测口径单一。 Falcor 框架、1 spp、1920×1080、四个场景(Veach Ajar、Carousel、Opera House、Bathroom)。没有移动端、没有低端 GPU、没有更高分辨率。Table 1 的 2.74× 是在这块硬件与这个分辨率上测的,换环境会变;原文提到性能随分辨率的扩展性更好(在补充材料里),但正文没有给数据。
十、2.74× 里既有算法收益也有工程收益,两类要分开看。 Table 1 的设计其实已经把它们分开了(虚线以上是省成本改动,以下是质量代价),但读摘要时容易混。具体地说:配对空间复用、新阈值、去相关属于算法;代码微优化、重放压缩、强制 NEE 重连、轮盘、统一 DI 与 GI、颜色噪声、去遮蔽属于工程与既有技术迁移。 而这里面最大的一步(轮盘,−10.29 毫秒)是工程而非算法。这条边界的意义是:一个团队想复现这个结果,未必要先做算法改进;把工程那几步做好,就能拿走一大半收益。
此外还有两处口径提醒,单独列在十条之外,因为它们属于「数字怎么读」:
其一,FLIP 而不是 PSNR。 本文所有误差都用 HDR FLIP 报,原文给的理由是它与切换对比图像时的感知差异高度一致。这是个有意的选择,也因为这套方法的收益有一部分是感知性的(相关性斑块在 PSNR 上未必显眼,在视觉上很明显)。读这张表时不要拿 FLIP 的差值去和别处的 PSNR 差值比较。
其二,「配对省一半」与「总账 2.74×」不是同一件事。 前者是空间复用这一列的局部账(6.99 → 4.11),后者是整帧账。而局部账里还有一步是净亏的:配对把空间复用拆成了两趟(预处理 + 重采样),所以拿不到理论上的 2 倍。凡是看到「某一步理论上省 50%」的说法,都该先问一句:它是不是把一趟活拆成了两趟。
13贡献块
贡献块
这篇论文解决的问题是什么。 ReSTIR PT 的理论(把路径样本在时空上复用)在 2022 年就成立了,但它的公开实现有三个现实问题:每帧 40 到 80 毫秒太慢;相关性斑块让降噪器把伪影当信号;重连阈值要按场景手调、在光泽材质上还不稳。原文把这类工作定性得很直接:ReSTIR 系方法的理论改进被反复研究,而朝向最优实现的算法改进与工程经验被普遍忽略。
它的核心贡献可以归成三件基建。
第一件,把空间复用那两趟搬运合成一趟(reciprocal neighbor selection)。 洞见是「我去邻居家取值、邻居来我家评估」这两趟用的是同一对映射,因此可以成对绑定、顺路办完。落实方式是用随机置换生成服从指定高斯分布的配对纹理,再靠翻转/镜像/转置/偏移让纹理每帧变化。收益是空间复用成本从 14.79 毫秒压到 4.11 毫秒。
第二件,把重连阈值从「人来调」换成「从几何算」(footprint-based reconnection criteria)。 原来的距离阈值与粗糙度阈值互相纠缠、还要按场景调。新判据的出发点是「理想 shift 的雅可比行列式近似为 1」,再把行列式拆成面积密度与角度密度两个比值,各自用光线 footprint 给出充分条件,最后把一堆推导收成一个常数 c(实测 0.02)。三条性质跟着来:光泽材质下更稳、不用按场景调、能更早重连(因此更便宜)。
第三件,用 duplication map 把相关性测出来再压下去。 机制朴素到近乎直白:数一数邻居里有多少像素和我拿着同一张样本(17×17 邻域、计数除以 288 得到 D ∈ [0,1]),再按 cCap = lerp(20, 1, D0.1) 自适应降低时间置信。代价是引入偏差,原文承认并量化了(困难场景 3.25%)。
再加上一组「不是新算法但很值钱」的工程改动:把直接光与全局光统一进同一组 reservoir(省掉一整遍 pass,还顺带提升直接光质量)、降低分歧的四项(条件移动、reservoir 88→64 字节、流压缩、强制 NEE 重连)、俄罗斯轮盘、向量权重治颜色噪声、对偶运动矢量治去遮蔽噪声。
三件事合起来的结果:四场景平均 35.73 → 13.04 毫秒(2.74×),加回质量项后 15.53 毫秒(仍 2.30×);Spaceship 场景 37.1ms/FLIP 0.321 → 12.6ms/FLIP 0.263;NSight 显示 warp 延迟 347k → 82k cycles。
在拆牌之前,先把这篇论文在方法谱系里的位置说清。ReSTIR 家族走到这一步,理论侧的空间已经很拥挤:新的重采样策略、新的 MIS 权重、新的候选来源,每隔一段时间就有一篇。而这篇论文选的是一个很少有人专门做的位置——它假设基础理论已经够好,转而处理「当你在真实引擎里把它跑起来时,会被什么拖住」。这个位置的价值随着 ReSTIR 被越来越多引擎采纳而上升,因为工程侧的问题是有共性的,而理论侧的改进往往是针对特定场景的。
这套打法里可以搬走的三张牌。
第一张,「先把『哪一步最贵』量出来,再决定优化什么」。这篇论文里最大的单步收益(−10.29 毫秒)来自俄罗斯轮盘,一件很老的技术;它值钱的原因是初始重采样是最贵的一步(路径最长最分歧)。收益跟着瓶颈走,不跟着新颖度走。
第二张,「能测的量不要建模」。相关性强不强,本来可以建一个关于复用链路的模型去推;作者的做法是直接数重复样本数,然后用一个 lerp 去调置信度。它的实现只剩三步(算图、查表、lerp),却把最棘手的一类伪影压了下去。凡是「某某性质很难建模」的地方,都要先问一句:它能不能被直接数出来?
第三张,「把经验阈值换成有推导的判据,然后收成一个旋钮」。原来的重连阈值是「距离不能太近、粗糙度不能太高」这类经验描述,互相纠缠且要按场景调;新判据从「理想映射的雅可比近似为 1」出发,用 footprint 给出充分条件,把整串推导收成一个常数 c。判据的性质从经验变成推导之后,调参负担才会真正消失——否则只是把一个阈值换成两个阈值。
它的位置。 在站内已发的 ReSTIR 家族里(篇目 02 的次表面散射、09 的混合方案、10 的 MegaLights、11 的 DDGI 对照位),这一篇的角色不一样:前几篇讲的是「ReSTIR 能用在哪」,这一篇讲的是「ReSTIR 要用起来还差什么」。它给出的答案集中在三类基建上,而这三类问题在任何做时空复用的管线里都会遇到。
14原文出处块
原文出处块
论文信息
- 标题:ReSTIR PT Enhanced: Algorithmic Advances for Faster and More Robust ReSTIR Path Tracing
- 作者:Daqi Lin、Markus Kettunen、Chris Wyman(NVIDIA)
- 发表:Proc. ACM Comput. Graph. Interact. Tech. 9(1), Article 13(2026 年 5 月);I3D 2026 Best Paper
- DOI:10.1145/3804494
- 篇幅:19 页,图 15 张(Fig. 1–15),表 1 张
- 硬件与口径:RTX 5880 Ada + Threadripper PRO 3975WX、Falcor 框架、1920×1080、HDR FLIP 为误差指标
许可与素材
本篇是本分区第一篇明确标注 Creative Commons 许可的 SIGGRAPH 系论文:原文版权块写明 This work is licensed under a Creative Commons Attribution 4.0 International License,即 CC BY 4.0。因此本篇的 15 张图在署名 + 未修改的前提下可原样引用,不再需要按非 CC 逐件许可的风险标注(对比篇目 02/03/09–11/13/15–20 的非 CC 处置)。
所有图均为原文截图原样引用、未修改,逐图署名格式为「图号 + 页码 + 版权 + 许可 + 未修改声明」。任何权利方异议可联系撤下。
复算台账
本篇正文所有数字均从原文表 1 与图 1、5、7、15 直接读取或按定义重算,涉及复算的 13 处:
1. 总加速比 35.73 / 13.04 = 2.74×(对应原文 average 2.74× speedup) 2. 带质量项后的加速比 35.73 / 15.53 = 2.30×(对应原文 still 2.30× faster) 3. 空间复用列 14.79 → 4.11 = 3.60×;配对那一步自身 6.99 / 4.11 = 1.70× 4. 俄罗斯轮盘单步 26.81 → 16.52 = −10.29 ms(−38%) 5. 统一 DI 与 GI 把「DI 及其他」列 5.24 → 1.00 = −81% 6. 质量代价 15.53 / 13.04 = 1.19×(+19%)(对应原文 increase average cost by 19%) 7. σ 换算 σ = √(8/(9π))·R,R = 30 → σ = 16.0(对应原文给出的 16.0) 8. 置换次数 n_σ ≈ ⌈σ²/2 + 0.5⌉,其中负幂项是原文标注的小 σ 拟合修正 9. 坐标差标准差 √(σ²/2 + σ²/2) = σ(配对两侧各偏移一次) 10. 首图读数 37.1 ms / FLIP 0.321 → 12.6 ms / FLIP 0.263(2.94×) 11. 图 8-1 对照:无去相关 12.9ms/0.297 → 有去相关 13.6ms/0.295(+0.7ms 换 FLIP −0.002) 12. NSight(Opera House):占用率 22.4% → 31.1% → 34.9%;活跃线程 15.3 → 19.9 → 20.6;warp 延迟 347k → 241k → 82k cycles(延迟相对基线 −76%) 13. σ 扫描:2.7/0.313、5.3/0.289、10.6/0.283(最低)、16.0/0.287;帧时间 3.72–3.99 ms 基本持平
待核
- 重复图的计数上限 288 对应 17×17 邻域能给出的最大共享数;原文写明了「除以 288」,但未解释该常数的推导(推测为该邻域内 reservoir 的上限,本稿按原文数字照录)。
- cCap 的自适应会产生偏差,原文给了 Kitchen 一个场景的 3.25% 平均绝对相对偏差,未给出跨场景的偏差统计,因此这个数不能当成普遍量级。
- 「配对空间复用没有完全省一半」的原因(拆成预处理 + 重采样两趟)是原文明确写出的,但两趟各自的开销未在正文列表,只能从表 1 里配对那一步的账面差(6.99 → 4.11)反推净收益。
- σ 扫描只给了四个取值,最优点是 10.6 而不是最终采用的 16.0;原文采用 16.0 的理由是与 R = 30 平均样本距离等价(比较公平),而不是它最优。这一点在摘要与结论里都没有体现。
- 性能随分辨率的扩展性(原文称更好)数据在补充材料,正文未给,本稿据此不引用具体倍数。