Chapter 39: Path Tracing
Path Tracing 解决的问题是:给定一帧画面中的相机、几何体、材质和光源,如何用有限数量的随机光路估计像素接收到的全局光照。读完本章后,读者应能追踪一条 camera path 如何从像素出发,经过 surface bounce、BRDF sampling、light sampling、throughput 更新和 sample accumulation,最后变成一帧带噪声但可收敛的图像。
本章贯穿使用一个室内 frame:相机看向一个封闭房间,左墙为红色漫反射材质,右墙为绿色漫反射材质,中央有一个粗糙金属球,天花板上有一个小矩形 area light,背景环境为黑色。这个场景足够小,但会同时暴露路径追踪的主要问题:墙面颜色渗透来自多次反弹,小光源会制造高方差,金属球需要 BRDF 方向采样,低 sample count 会产生颗粒噪声,实时版本还需要时间累积、空间复用和 denoiser。
路径追踪的工程结论可以先压缩成一句话:它把一帧图像拆成大量随机光路估计,每条光路用概率密度函数、BRDF、几何项、可见性和 throughput 计算贡献;画质来自样本平均,性能来自把有限光线分配给高贡献方向,并把可复用的光照结果安全地带到后续像素或后续帧。
本文会把数学模型、shader 执行、GPU 资源和调试证据分开讲。数学部分解释每条 path 的权重,shader 部分解释每个 bounce 做什么,GPU 资源部分解释 ray payload、acceleration structure、history buffer、G-buffer 和 cache 如何参与,调试证据部分解释应观察噪声、firefly、ghosting、漏光和 GPU ray time 的哪条路径。
下面这张图限定本章讨论的基本 frame path。它只覆盖从相机到光源的单向路径追踪,并把实时近似放在后处理和复用阶段;双向连接、photon map 和 irradiance cache 的细节会在相邻章节展开。
图中的主循环发生在 shader 或 ray tracing pipeline 中:每个像素生成一个或多个 camera ray,命中表面后读取几何和材质,分别估计直接光与下一次反弹,然后把当前样本写入 accumulation buffer。实时渲染会把当前帧、上一帧和邻近像素的样本继续输入复用与降噪阶段。离线路径追踪可以主要依赖更多 samples per pixel;实时路径追踪需要在极低样本数下维持稳定画面。
39.1 Path Tracing 的基本理念与流程
Path Tracing 的工作定义是:从相机出发构造随机光路,并用 Monte Carlo 估计渲染方程中的积分项。这里的 path 是一串顶点,例如 camera → first hit → second hit → light。每个顶点保存位置、法线、材质、入射方向、出射方向和概率密度。渲染器把大量 path 的贡献相加并求平均,得到像素的 radiance。
在室内 frame 中,左墙红色反射不会只影响左墙本身。相机射线命中地面后,下一条反弹射线可能打到左墙,再反射到天花板光源附近。这个路径把红墙的能量带到地面,所以地面会出现轻微红色间接光。传统局部光照模型通常需要额外的 ambient 或 lightmap 才能表达这个效果;路径追踪把它放进同一条随机光路中估计。
路径追踪的核心状态通常可以压缩为四个变量:radiance 保存当前 path 已经累加到像素的光,throughput 保存从相机到当前顶点仍然保留下来的能量权重,ray 保存下一次追踪的起点与方向,depth 保存已经发生的反弹次数。throughput 的意义很关键:它把此前所有 BRDF、余弦项和 PDF 修正乘在一起,后续命中光源或环境时,光源 radiance 会乘以这个权重再写入像素。
一个最小路径追踪循环可以写成下面的伪代码。它省略了介质、透明材质和 spectral rendering,只保留本章讨论的 surface path 主干。
Spectrum tracePath(Ray ray, RNG& rng) {
Spectrum radiance = Spectrum(0.0f);
Spectrum throughput = Spectrum(1.0f);
for (int depth = 0; depth < maxDepth; ++depth) {
Hit hit = traceClosest(ray);
if (!hit.found) {
radiance += throughput * sampleEnvironment(ray.direction);
break;
}
Material material = loadMaterial(hit.materialId);
ShadingFrame frame = buildShadingFrame(hit.normal, ray.direction);
if (hit.isEmitter) {
radiance += throughput * emittedRadiance(hit, -ray.direction);
}
DirectSample light = sampleDirectLight(hit.position, frame, material, rng);
radiance += throughput * light.contribution;
BSDFSample bounce = sampleBSDF(material, frame, rng);
if (bounce.pdf <= 0.0f || bounce.weight.isBlack()) {
break;
}
throughput *= bounce.weight;
ray = spawnRay(hit.position, bounce.direction);
if (depth >= rouletteStart && terminateByRussianRoulette(throughput, rng)) {
break;
}
}
return radiance;
}
这段伪代码回答的是 shader 里每条 path 的数据路径。traceClosest 访问 acceleration structure,输出第一个交点;loadMaterial 从材质 buffer 或 texture 中读取 BRDF 参数;sampleDirectLight 生成 shadow ray,回答“当前点能看到哪部分光源”;sampleBSDF 生成下一条反弹 ray,回答“能量下一步往哪里走”;spawnRay 需要给起点加一个很小的偏移,降低自相交导致的黑斑或亮斑概率。
最小循环中的直接光采样通常也叫 next event estimation。它在每个非 specular 表面主动连接一次光源,使小光源贡献进入显式估计路径。在本章的室内 frame 中,天花板 area light 很小;纯 BRDF 反弹很少命中它,画面会出现大量黑样本和少数极亮样本。直接光采样把“选中光源上的一点并测试可见性”变成显式步骤,能显著降低直接光噪声。
throughput 更新的基本形态是 throughput *= f(wo, wi) * abs(dot(n, wi)) / pdf(wi)。这里 f 是 BRDF 值,wi 是下一条反弹方向,pdf(wi) 是采样方向的概率密度。这个除以 PDF 的动作保证了估计不会因为“某些方向被更频繁抽中”而改变平均能量;高概率方向单次权重较小,低概率方向单次权重较大。
路径终止有两个层次。第一层是固定最大深度,例如 4 次或 8 次 bounce,用于控制最坏情况成本。第二层是 Russian roulette,它根据 throughput 大小随机结束低贡献 path,并对存活 path 做权重补偿。它的工程作用是把时间预算集中到仍然可能贡献亮度的路径上,同时让平均估计保持一致。实现时通常在前几次 bounce 后才启用,原因是浅层反弹承担主要可见照明,过早终止会让噪声集中在大面积区域。
路径追踪输出的单帧样本天然带噪声。像素最终颜色来自 sample accumulation:第 n 个样本返回 L_n,累积颜色可写成运行平均 C_n = C_{n-1} + (L_n - C_{n-1}) / n。离线渲染可以让 n 增长到数百或数千;实时渲染常常每帧每像素只有 1 条或少数几条 path,所以必须把 accumulation 拆到时间维度,并配合重投影、复用和降噪。
PBRT 第四版的 Path Tracing 章节展示了路径积分、Russian roulette 和增量构造 path 的理论来源;A Better Path Tracer进一步说明了直接光采样、MIS、light sampler 和 path regularization 如何降低方差。工程阅读时应把这些内容对应到本节的四个状态变量,让公式落回 shader 状态和样本权重。
39.2 重要性采样与权重调整策略
重要性采样的目标是把有限样本投向高贡献区域。路径追踪估计的是积分,随机方向的选择分布会直接决定噪声形态。采样分布和真实贡献越接近,单个样本的权重变化越小,画面越稳定;采样分布和贡献错位时,少数样本会携带极大权重,firefly 和颗粒噪声会集中出现。
在室内 frame 中,同一个表面点至少面对四类采样对象:BRDF 方向、天花板 area light、环境贴图方向和相机像素内位置。BRDF sampling 适合处理金属球上的窄高光,因为粗糙度低时贡献集中在反射方向附近。Light sampling 适合处理小矩形灯,因为从漫反射墙面随机按余弦半球采样时命中灯的概率很低。Environment map sampling 适合处理 HDR 天空中太阳附近的高亮区域。Pixel sampling 适合处理几何边缘和纹理高频细节。
一个采样策略要能写出两件事:如何生成样本,以及这个样本的 PDF 是多少。没有 PDF,后续就无法计算 contribution / pdf,也无法和其他策略做 multiple importance sampling。实际工程中最常见的错误是采样方向来自一个分布,权重计算却使用另一个分布;这种错误会表现为能量偏暗、局部过亮或角度相关的亮度漂移。
| 采样对象 | 适合的贡献区域 | 需要保存的 PDF | 容易出现的症状 |
|---|---|---|---|
| BRDF sampling | glossy 高光、镜面反射方向、粗糙材质的半球散射 | 方向 PDF | 小光源直接光噪声高 |
| Light sampling | 小面积光源、多光源直接照明、阴影边界 | 光源选择 PDF 与光源表面 PDF | glossy 反射中偶发大权重 |
| Environment sampling | HDR environment 的太阳、窗外亮区、天空梯度 | 球面方向 PDF | 高亮环境点产生 firefly |
| Pixel sampling | 边缘抗锯齿、景深、运动模糊 | 像素滤波或镜头采样 PDF | 低样本下边缘闪烁 |
Multiple Importance Sampling(MIS)用于合并多个采样策略。它的判断非常直接:BRDF sampling 和 light sampling 都能估计同一项直接光贡献,但它们各自在不同场景下噪声较低。MIS 给每个样本一个权重,使低 PDF 或低可靠性的策略对最终估计影响下降。PBRT 中常用的 power heuristic 可以理解为“谁更可能生成当前这个高贡献样本,谁就获得更高权重”。
在天花板小灯照亮粗糙金属球的例子中,单纯 light sampling 会经常抽到灯面,但抽到的方向未必落入金属球的高光 lobe;单纯 BRDF sampling 会沿高光方向抽样,但命中小灯概率低。MIS 同时使用两个样本:一个从光源出发形成 shadow ray,一个从 BRDF 分布出发继续追踪。两个结果按各自 PDF 加权后相加,通常比任一单一策略稳定。
权重调整还要处理 light area 和 solid angle 的转换。采样 area light 时,渲染器常先在光源表面抽一个点,此时得到的是面积 PDF;shader 计算表面点到光源点的方向贡献时,需要把面积 PDF 转成方向 PDF。转换项包含距离平方和光源法线夹角。这个步骤出错时,近处光源会过亮或过暗,斜视角光源的贡献也会异常。
Environment map 的重要性采样通常基于亮度分布构建二维 CDF 或 alias table。对 HDR environment 来说,太阳区域可能只占很小角度,却贡献大部分能量。均匀半球采样会让大量样本落在低亮天空区域,偶尔命中太阳时产生极大权重。按亮度采样能把更多方向投向太阳附近,但仍需保留球面参数化带来的 sin(theta) 面积修正。
BRDF sampling 的 PDF 必须和材质模型一致。Lambert 漫反射常用 cosine-weighted hemisphere sampling,因为贡献中天然含有 cos(theta);GGX microfacet 高光常按 half vector 分布采样,再转换到出射方向 PDF。材质 shader 中只实现 BRDF 值而没有对应采样函数,路径追踪就会退化成高噪声估计;只实现采样函数而没有正确 PDF,能量就会失真。
重要性采样的检查顺序可以固定为五步。先确认样本来自哪个分布,再打印或可视化 PDF 是否为正值,再确认贡献项和 PDF 在同一个测度下计算,然后检查 MIS 权重是否对所有可生成该样本的策略求 PDF,最后用简单场景验证能量趋势。简单场景可以选择白色漫反射地面加一个 area light;光源面积扩大时阴影变软,亮度按发光强度设定变化,噪声应随采样策略改善而下降。
39.3 实时路径追踪的近似方法
实时路径追踪的核心约束是 ray budget。离线路径追踪可以用大量 samples per pixel 慢慢收敛;实时 frame 需要在 16.6ms、8.3ms 或更紧的预算内完成相机射线、求交、材质读取、直接光、若干次反弹、复用、降噪和呈现。于是实时系统会把“无偏且高样本”的目标调整成“低样本、稳定、可交互、误差可控”。
最常见的实时路径追踪配置是每帧每像素 1 条 primary path,并限制 bounce 数。第一反弹处理最清晰的可见表面,第二反弹处理主要间接光,后续高阶反弹交给 radiance cache、probe cache 或环境近似。这样做的结果是:直接可见材质仍然由真实 ray 命中决定,间接光中的低频部分通过复用和缓存补足,高频困难路径允许降级为更平滑的近似。
Temporal accumulation 是实时路径追踪的第一层支撑。当前帧渲染出的 noisy radiance 会通过 motion vector 投影到上一帧 history buffer 对应像素,再按置信度混合。这个过程需要 G-buffer guide:depth 用于确认是否是同一表面,normal 用于确认朝向是否匹配,material id 或 roughness 用于确认材质是否发生变化,motion vector 用于定位上一帧样本。history 合法时可以获得近似多帧样本平均;history 失效时必须快速切回当前帧结果。
Spatial reuse 是第二层支撑。路径追踪的每个像素样本都很昂贵,相邻像素如果位于相同表面且材质接近,就可能共享部分候选光照样本。Reservoir sampling 系列方法把候选 light sample 或 path sample 存入一个小结构,再在时间和空间中合并。NVIDIA 的 ReSTIR 论文页面给出了一个典型方向:用 reservoir、temporal resampling 和 spatial resampling 在动态多光源场景中复用重要样本。
实时路径追踪通常会把渲染拆成多个 pass,让每个 pass 只承担明确的数据转换。一个常见结构是:G-buffer pass 生成可见表面属性;path tracing pass 生成当前 noisy radiance、first hit normal、albedo 和 moments;temporal pass 做重投影和 history validation;spatial pass 做 guided filter;denoise pass 输出稳定 radiance;composite pass 做 tone mapping 和 UI 合成。拆分 pass 可以让每个阶段的资源输入输出更清晰,也方便 profiler 定位瓶颈。
低 sample count 会改变美术和工程边界。粗糙材质、漫反射墙面和大面积光源容易被 temporal accumulation 稳定;镜面反射、小光源、薄几何、快速运动物体和透明材质更容易触发 history rejection。实时系统通常会为这些情况设置不同路径:rough reflection 使用半分辨率或缓存,mirror reflection 保留高质量 ray,透明材质限制深度或回退到 raster transparency,快速运动区域降低 history 权重。
Denoiser 是实时路径追踪输出链路中的正式渲染阶段。它读取 noisy radiance、normal、albedo、depth、roughness、motion vector 和 history moments,估计哪些差异来自噪声,哪些差异来自真实几何或材质边界。一个合格 denoiser 不应把红墙颜色渗透抹成灰色,也不应把金属球高光拖成残影。调试时要分开查看输入 noisy buffer、history buffer、variance buffer 和最终输出。
实时近似还包括分辨率和频率调度。间接 diffuse GI 可以低分辨率计算后上采样;高光反射可以按 roughness 决定 ray 数;低变化区域可以隔帧更新;屏幕边缘或运动区域可以增加当前帧权重;远处小物体可以使用 probe 或 lightmap。所有调度策略都应能回答一个问题:减少的是哪类 ray、哪类 texture 访问、哪类同步或哪类缓存占用,画质损失会落在哪种可见现象上。
可用的工程判断顺序是:先确定每帧 ray budget,再决定哪些光照项必须用真实 ray,接着把低频间接光交给时间积累或缓存,再为 history rejection 设计边界条件,最后用分离 buffer 检查噪声来自采样、复用、降噪还是 tone mapping。这个顺序能防止把所有问题都归给 denoiser,也能防止用更多 ray 掩盖资源状态和重投影错误。
39.4 噪声抑制与后处理方法
路径追踪噪声本质上是 Monte Carlo 方差的视觉表现。它会在不同光照项中呈现不同形态:直接光采样不足会造成阴影边界颗粒,小光源和高亮环境会造成 firefly,glossy 反射采样不足会造成闪烁斑点,间接 diffuse 采样不足会造成低频脏块,temporal history 错误会造成拖影和残影。噪声处理的第一步是把这些来源分离,再决定采样、复用或滤波策略。
Variance estimation 用于判断某个像素或区域的当前结果可信程度。最简单的做法是在 accumulation 中保存一阶矩和二阶矩,例如当前 radiance 均值与平方均值,由此估计方差。实时系统还会把 variance 按光照项拆开,例如 direct diffuse、indirect diffuse、specular reflection 分别估计。拆分后的好处是粗糙墙面可以使用强一点的空间滤波,而镜面高光需要更保守的 history 和更小的滤波半径。
Temporal reprojection 的核心输入是 motion vector。当前帧像素先通过 motion vector 找到上一帧对应位置,再比较 depth、normal 和 material 特征。匹配成功时,history radiance 可以参与累积;匹配失败时,当前帧需要重新开始。匹配规则过松会出现 ghosting,规则过紧会导致画面在运动时重新变噪。室内 frame 中,如果金属球移动,球边缘附近的 history 必须被拒绝,否则旧位置的高光会残留在背景墙上。
Normal 和 albedo guide 用于保护几何边界与材质边界。Denoiser 看到相邻像素 radiance 差异时,需要判断这是噪声还是真实表面变化。normal 差异大,通常说明跨越了几何边缘;albedo 差异大,通常说明跨越了材质边界。滤波权重应在这些边界下降。红墙和白地面的交界处就是典型例子:间接光可以在地面上平滑,但不能把红墙 base color 直接扩散到地面纹理边界之外。
History rejection 是实时稳定性的关键。常见条件包括 depth 差异超过阈值、normal 夹角过大、material id 变化、roughness 变化、disocclusion、光源剧烈变化和 radiance 差异异常。这里的阈值应按空间和材质调整:远处 depth 差异可以容忍更大世界距离,近处薄物体要更严格;高 roughness 表面可以更依赖 history,镜面表面要更保守。
Firefly 处理需要区分采样问题和后处理问题。Firefly 是少数样本携带极高权重的结果,常见来源是小 PDF、高亮环境、小光源、caustics、错误的 area-to-solid-angle 转换或材质能量异常。后处理可以使用 luminance clamp、robust statistics 或 neighborhood clamping 降低极端值,但采样和权重错误必须在 path tracing pass 内修正。只靠 clamp 会压暗真实高光,也会掩盖 PDF 错误。
后处理链路中的 tone mapping 也会改变噪声观感。路径追踪输出通常是线性 HDR radiance,少数极亮样本在线性空间占据很大能量,tone mapping 后可能变成明显亮点。降噪通常应在线性空间或经过明确变换的 radiance 空间工作,再进入 exposure、tone mapping 和 gamma 输出。把 LDR 后的颜色拿来做主要降噪会让高光、阴影和颜色渗透的统计关系失真。
下面的排查顺序适合定位一帧路径追踪画面的噪声来源。先关闭 denoiser 查看 raw radiance,确认噪声位于 direct、indirect 还是 specular buffer;再关闭 temporal accumulation,确认问题来自当前帧采样还是历史复用;接着可视化 PDF、throughput、sample count、variance、normal、albedo 和 motion vector;然后单独固定光源、相机或材质,观察噪声是否随某个输入变化;最后再调滤波半径、history 权重和 clamp 阈值。
一个稳定的 denoiser 输出应满足三条可观察条件。静止画面中,噪声随帧数下降,边缘不出现持续抖动;运动画面中,新暴露区域短暂变噪,但不会拖出旧物体轮廓;光源变化时,间接光允许有短暂收敛过程,但不会长时间保留旧亮度。任何一条失败,都应回到 history validation、variance estimation 或输入 guide buffer 检查。
39.5 性能优化:分布式光线与光照缓存
路径追踪性能优化要先确定成本属于哪条路径。Primary ray 成本通常受分辨率和 acceleration structure traversal 影响;shadow ray 成本受直接光采样数量和遮挡复杂度影响;bounce ray 成本受最大深度、材质分布和分支发散影响;材质读取受 texture cache 和 buffer layout 影响;denoiser 成本受滤波半径、history 访问和全屏 pass 数量影响。把这些成本混成“路径追踪很慢”会让优化失去方向。
分布式光线在工程中可以理解为把有限 ray 分配到不同维度:像素内位置、时间、光源候选、BRDF 方向、反弹深度、空间邻域和材质类别。离线渲染可以在同一像素内堆叠大量样本;实时渲染会把这些样本分散到多帧、多像素和多缓存结构中,再用统计权重合并。关键约束是复用的样本必须能解释当前像素的光照项,否则就会引入拖影、漏光或能量偏差。
Reservoir sampling 适合在大量候选中保留少数高价值样本。一个 reservoir 通常保存候选样本、累计权重、候选数量和目标函数值。当前像素可以先从多个 light sample 中抽一个,再和上一帧同像素 reservoir 合并,还可以和邻近像素 reservoir 合并。对直接光来说,reservoir 保存的是某个光源点与权重;对更一般的 path reuse 来说,reservoir 可能保存一段 path 或某个连接顶点。
Reservoir 的收益来自两点。第一,它用很小存储表示大量候选的抽样结果,适合 GPU 上每像素保存。第二,它允许把“候选生成”和“可见性测试”分开,减少昂贵 shadow ray 的数量。代价是实现必须处理样本域转换、目标函数变化、邻域相关性和历史失效。室内 frame 中,天花板小灯的候选可在相邻墙面像素间复用;金属球上的镜面高光候选复用范围要小,因为法线和 BRDF lobe 变化快。
Radiance cache 适合处理低频、多次反弹的间接光。它可以在世界空间、屏幕空间、probe grid 或神经网络表示中保存某个位置和方向附近的入射 radiance。实时路径追踪常把前几次可见反弹用真实 ray 计算,把更深层 bounce 查询 cache。这样可以降低递归深度和长路径噪声,同时保留第一可见表面的高频几何细节。Real-time Neural Radiance Caching for Path Tracing展示了把 radiance cache 放入实时 path tracing 的一种研究路线。
Probe cache 是更传统、更易集成的间接光缓存。它在世界空间布置 probe,probe 存储低频 irradiance 或 radiance,并在表面点插值查询。Probe 对 diffuse GI 友好,对 glossy reflection 和细薄遮挡支持较弱。室内 frame 中,probe 能稳定表示墙面颜色渗透和大面积间接光;金属球上清晰反射的天花板灯仍需真实 ray 或专门的 reflection path。
Path guiding 通过历史样本学习哪些方向贡献高,并在后续 bounce 中提高这些方向的采样概率。它和 reservoir、cache 的位置不同:guiding 改变的是采样分布,cache 改变的是某些光照查询的来源,reservoir 改变的是候选样本的保留和复用方式。一个工程系统可以同时使用三者:path guiding 生成更好的反弹方向,reservoir 复用直接光候选,radiance cache 提供深层间接光近似。
性能调优需要配合 profiler 和可视化 buffer。GPU profiler 中要区分 ray traversal time、any-hit 或 closest-hit shader time、texture sampling time、denoiser full-screen pass time、barrier 和 queue wait。RenderDoc、Nsight Graphics、PIX 或 Xcode GPU tools 能帮助检查 dispatch、shader table、resource binding 和 barrier;不同 API 的命名不同,但要回答的问题相同:哪一个 pass 消耗主要时间,消耗来自 ray 数、shader 分支、带宽、同步还是全屏滤波。
优化顺序可以固定为:先限制最大 ray 数并记录每类 ray 的数量;再按 pass 统计 GPU 时间;接着可视化 depth、normal、roughness、variance 和 history validity;然后为 direct、indirect、specular 三类光照分别选择采样、复用或缓存策略;最后检查画质回归,重点看阴影边界、颜色渗透、金属高光、移动物体和 disocclusion 区域。这个顺序让优化始终绑定到可观察证据,并减少对单一经验参数的依赖。
一个实用的实时路径追踪预算可以这样分配:primary ray 全分辨率每像素 1 条,direct light reservoir 每像素保留 1 个候选,indirect diffuse 半分辨率或 checkerboard 更新,specular 根据 roughness 决定真实 ray 或缓存查询,denoiser 使用 normal、albedo、depth 和 motion vector 做 guided reconstruction。这个配置只是一种起始预算,但它给出一条可复查的数据路径:真实 ray 保留可见表面和关键高光,复用结构承接直接光候选,cache 承接低频间接光,denoiser 负责把低样本结果稳定成帧。
最小自检任务
给定一个 1280×720 的室内路径追踪 demo:白色地面、红色左墙、绿色右墙、粗糙金属球、天花板小矩形 area light。当前实现每帧每像素 1 条 path,最大 3 次 bounce,开启 temporal accumulation 和 denoiser。画面症状是:静止时墙面间接光有明显颗粒;相机横移时金属球边缘有拖影;小灯附近偶发白色 firefly;GPU profiler 显示 path tracing pass 与 denoiser pass 都占用较高时间。请按本章方法给出排查顺序,并说明每一步要观察哪个 buffer 或指标。
答案要点
先关闭 denoiser 观察 raw radiance,并把 direct diffuse、indirect diffuse 和 specular 分开显示。墙面间接光颗粒如果主要出现在 indirect diffuse buffer,应检查 bounce 采样数、throughput 分布、variance buffer 和 temporal accumulation 的有效样本数;direct buffer 稳定时,小灯直接采样路径基本成立。
接着关闭 temporal accumulation 或把 history 权重降到很低,观察金属球边缘拖影是否消失。拖影消失说明问题来自 history reprojection 或 history rejection。需要检查 motion vector、depth 差异、normal 夹角、roughness/material id 和 disocclusion mask。金属球边缘属于几何和反射快速变化区域,history 权重要比粗糙墙面更保守。
然后定位 firefly 来源。可视化 sample luminance、PDF、throughput 和 light sample 类型。小灯附近白点如果伴随极小 PDF 或极大 throughput,应优先检查 area light 的面积 PDF 到方向 PDF 转换、MIS 权重、BRDF sampling 与 light sampling 的 PDF 是否一致,以及 luminance clamp 是否压制了异常但保留真实高光。
再用 profiler 按 pass 拆分成本。Path tracing pass 需要统计 primary、shadow、bounce ray 数量以及 closest-hit shader 时间;denoiser pass 需要检查全屏访问次数、滤波半径、history buffer 读取和 barrier。若 indirect diffuse 噪声高且 ray 成本高,可以考虑半分辨率更新、spatial reuse、radiance cache 或 probe cache;若 denoiser 成本高,应先缩小高方差区域的滤波范围,并复查 guide buffer 的有效性。
最后做回归观察。静止画面中间接光应随帧数稳定下降噪声;横移时金属球边缘允许短暂变噪,但旧高光轮廓不应残留;小灯真实高光应保留,孤立异常白点应减少;GPU 时间应能对应到减少的 ray 类型、缓存查询或滤波范围。
本章知识点总结
- Path 定义:路径追踪从相机出发生成一串随机表面顶点,并用这些顶点估计像素接收到的全局光照。
- 贯穿状态:
radiance、throughput、ray和depth构成最小路径追踪循环的核心状态。 - 直接采样:next event estimation 在表面点主动连接光源,能显著降低小光源直接照明的方差。
- 权重修正:BRDF、余弦项和 PDF 共同决定单次反弹的 throughput 更新,PDF 必须对应真实采样分布。
- 路径终止:最大深度控制最坏成本,Russian roulette 把更多预算留给高贡献路径并保持平均估计一致。
- 重要采样:BRDF sampling、light sampling、environment sampling 和 pixel sampling 分别覆盖不同高贡献区域。
- MIS 作用:Multiple Importance Sampling 按各策略生成当前样本的可靠程度分配权重,降低单一采样策略的高方差。
- 实时约束:实时路径追踪受 ray budget 限制,需要把样本分散到当前帧、历史帧、邻域像素和缓存结构中复用。
- 历史累积:Temporal accumulation 依赖 motion vector、depth、normal 和材质特征验证上一帧样本是否还能服务当前像素。
- 降噪输入:Denoiser 应读取 noisy radiance、normal、albedo、depth、roughness、motion vector 和 variance 来区分噪声与真实边界。
- Firefly 来源:极亮孤立点通常来自小 PDF、高 throughput、高亮环境、小光源或测度转换错误。
- Reservoir 复用:Reservoir sampling 用小存储保留高价值候选,并支持跨时间和空间合并光照样本。
- Radiance cache:Radiance cache 和 probe cache 适合承接低频多次反弹间接光,关键高光仍应保留真实 ray 或专门路径。
- 优化顺序:性能调优应先统计 ray 数和 pass 时间,再按 direct、indirect、specular 分别选择采样、复用、缓存或降噪策略。