Skip to main content

Chapter 73: Denoising and Reconstruction

本章讨论 Path Tracing 和低采样实时光追中的去噪与重建。读者读完后应能定位一张 noisy beauty 中的噪声来源,判断哪些辅助 buffer 能支持重建,区分传统滤波、时空滤波和 ML denoiser 的边界,并把去噪 pass 安排进渲染管线。

贯穿本章的材料是一帧室内路径追踪画面:相机看向一张 glossy 木桌,桌面上有金属杯、玻璃杯、小面积窗光和一块带细纹理的地毯。渲染器每像素只追踪 1 到 4 条路径,输出 noisy beauty,同时输出 albedo、normal、depth、motion vector 和材质 roughness。画面中的墙面低频噪声、金属杯高亮 firefly、桌面反射拖影和地毯纹理模糊,分别对应不同的去噪失败模式。

Denoising 的输入是有采样误差的图像,reconstruction 的目标是从这些样本、辅助特征和时序历史中恢复稳定图像。这里的“恢复”带有估计含义:它会降低方差,也可能引入偏差。工程判断的核心因此分成三步:先判断噪声来自采样、材质还是时间历史,再判断辅助特征是否可信,最后选择 spatial、temporal 或 ML 路径,并用参考图和动态画面复查误差。

本文会使用两个公开工程作为边界参照。Intel Open Image Denoise 的文档展示了离线渲染常见的 noisy color、albedo、normal 输入方式;NVIDIA Real-Time Denoisers 的 README 展示了实时路径中 normal、roughness、viewZ、motion vector、hit distance 等 G-buffer guide 如何服务时空去噪。它们代表两类管线:一类偏最终帧质量,一类偏实时帧间稳定性。

73.1 噪声源与采样误差的数学基础

Monte Carlo rendering 把像素颜色看作积分估计。一个像素的最终辐射亮度可以写成期望值,渲染器用有限路径样本估计它:L^=1Ni=1NLi\hat L = \frac{1}{N}\sum_{i=1}^{N} L_i。当样本彼此独立且分布稳定时,估计量方差大致按 σ2/N\sigma^2/N 下降。这个关系解释了路径追踪噪声的基本形态:采样数量翻倍只让标准差按平方根下降,低采样画面天然带有明显随机误差。

这帧室内图中,墙面的大面积漫反射区域会出现细颗粒噪声。墙面材质平滑、几何连续,局部像素的真实颜色变化很慢,噪声主要来自有限样本。对这类区域,空间滤波和 ML denoiser 都容易得到稳定结果,因为相邻像素的几何和材质特征一致。

金属杯边缘的亮点属于更困难的样本分布。小面积窗光、镜面反射和高动态范围光源会让少数路径携带远高于平均值的能量,这类样本在画面上表现为 firefly。Firefly 的问题不在于像素“颜色随机”,而在于样本分布存在高能长尾。简单均值会被少数样本拉高,简单模糊又会把亮点扩散到周围像素。

采样误差还会被 light transport difficulty 放大。玻璃杯后的 caustics、金属杯上的窄高光、地毯纤维产生的高频遮挡,都会让有效样本概率下降。路径追踪器在这些位置可能连续多帧都没有采到关键光路,然后某一帧突然采到高能路径。视觉上表现为闪烁、局部爆点或细节忽隐忽现。

渲染去噪首先要把像素颜色分解成“信号变化”和“采样误差”。信号变化来自几何边界、法线突变、贴图纹理、材质 roughness、阴影边界和反射内容。采样误差来自有限路径数量、随机数序列、光源采样概率、路径终止和材质采样分布。去噪器要压低后一类变化,同时保留前一类变化。

一个可复用判断顺序如下:先观察 noisy beauty 的高频变化是否跟 normal、depth 或 albedo 边界对齐;再观察亮点是否超过相邻像素能量范围;再比较同一相机位置多帧噪声是否独立跳动;最后用高采样 reference frame 判断细节属于真实信号还是随机误差。这个顺序能把“该模糊的噪声”和“该保留的纹理”分开。

在本章贯穿画面中,墙面颗粒不跟任何几何或贴图边界对齐,属于可滤除噪声;地毯细纹跟 albedo 高频变化对齐,属于应保留信号;金属杯 firefly 能量远高于邻域且位置随机,适合先做样本 clamp 或 firefly suppression;桌面反射中的拖影跟 motion vector 和 hit distance 相关,单帧空间滤波无法独立判断。

73.2 Classical Denoising Filters and Failure Modes

传统去噪滤波器的核心思路是利用局部相似性。Box blur 和 Gaussian blur 假设邻域像素属于同一信号,Bilateral filter 进一步加入颜色、法线或深度差异作为权重,A-trous wavelet filter 用多尺度稀疏卷积扩大感受野。它们的优势是行为可解释、成本可控、容易嵌入 compute pass;限制是对真实信号和采样误差的区分依赖人工设计的权重。

在室内图的墙面区域,Gaussian 或 A-trous 滤波能快速降低颗粒。墙面 normal、depth、albedo 都近似连续,邻域颜色变化主要来自方差。此时扩大 kernel 半径会带来稳定收益,画面细节损失较小。这个区域适合把方差估计作为滤波强度依据:方差高时增加滤波半径,方差低时保留原始颜色。

Bilateral filter 解决的是边缘保护问题。它根据空间距离和特征差异共同分配权重,例如位置接近、normal 接近、depth 接近、albedo 接近的像素权重更高。桌面和墙面交界处如果只做颜色模糊,桌面颜色会渗入墙面;加入 depth 和 normal guide 后,跨几何边界的样本权重会下降,边缘更稳定。

Bilateral 思路的失败点来自 guide buffer 本身。玻璃杯区域的 depth 可能对应前表面、后表面或折射后背景,normal 也可能不代表最终可见光路。用这类 guide 强行保护边缘,会让噪声停留在透明物体内,或把背景纹理误判为前景细节。透明、体积、毛发和强折射区域通常需要独立策略。

Laplacian 和频域类方法更关注高频分量。它们能定位局部边缘和纹理,但 MC 噪声本身也大量落在高频区域。地毯细纹和随机颗粒在频率上可能相似,单靠频域强度无法可靠区分。工程上要把 albedo、normal、depth 或材质 roughness 引入判断,才有机会保留地毯纹理并压低随机噪声。

传统滤波器还容易产生 bias。Bias 指输出图像的期望值偏离真实 reference。过强滤波会压低金属杯高光,扩大阴影半影,抹掉桌面反射中的细结构。低方差图像不等于正确图像;一个过度平滑的结果可能比 noisy frame 更稳定,却更偏离真实光传输。

下面的流程图描述传统滤波在一帧中的判断路径。它只覆盖不使用神经网络的空间滤波和少量时序反馈,重点是每一步依赖的输入证据。

这条路径的关键在于“边界是否可信”。法线和深度来自 primary hit 时,它们对不透明表面很有效;在反射、透明、体积、薄几何和运动遮挡中,它们只解释部分光路。传统滤波器没有能力自己理解光路,因此输入 guide 的语义边界必须由渲染管线提供。

一套稳定的 classical denoising 检查顺序是:先禁用 temporal feedback,只看单帧空间滤波是否破坏几何边;再固定滤波半径,逐个加入 color、normal、depth、albedo 权重;然后用高采样 reference 比较边缘、纹理和高光;最后恢复 temporal accumulation,检查动态相机下是否出现 ghosting。这样能把空间滤波问题和历史复用问题分开定位。

73.3 ML 驱动的图像去噪技术

ML denoiser 把去噪看作有监督或自监督的图像重建问题。输入通常包含 noisy beauty 和辅助 buffer,输出是一张接近高采样 reference 的图像。和手写滤波器相比,神经网络可以从数据中学习复杂的非线性关系,例如 albedo 边界、normal 边界和颜色噪声之间的组合规则。

离线渲染常见的 ML 输入是 noisy color、albedo 和 normal。Intel Open Image Denoise 的 RT filter 文档示例就使用 color 作为 beauty 输入,并可接入 albedo、normal 辅助图。这个设计对应离线帧的常见假设:相机和场景已经固定,目标是从低采样结果重建高质量最终帧。

实时渲染的 ML 或非 ML 时空 denoiser 通常需要更多动态信息。motion vector 说明当前像素在上一帧的位置,depth 或 viewZ 辅助判断遮挡变化,roughness 帮助区分 diffuse 与 specular lobe,history buffer 提供多帧采样。NRD 这类实时库把 normal、roughness、viewZ、motion vector、hit distance 等 guide 放在核心位置,原因是实时路径每帧样本很少,时间维度提供了主要样本来源。

ML denoiser 的优势来自训练集中的先验。它可以学习“墙面低频颜色应平滑”“几何边界应保持锐利”“贴图 albedo 高频应保留”这类模式。对于室内图的墙面、木纹和地毯,它可能比固定 kernel 更好地平衡噪声和细节,因为网络能联合观察多个 feature buffer。

ML denoiser 的风险也来自训练先验。网络见过的材质、光照、相机曝光和采样分布会影响输出。训练集覆盖不足时,玻璃杯后的 caustics 可能被当作噪声压掉,金属杯上的窄高光可能被重建成更宽的亮斑,地毯纹理可能被生成出参考图中不存在的细节。这个偏差在静帧中可能看起来干净,在镜头运动中会变成闪烁或细节漂移。

特征 buffer 的质量决定 ML 重建的上限。Noisy beauty 提供光照结果,albedo 提供表面颜色边界,normal 提供局部几何方向,depth 提供遮挡层级,motion vector 提供历史对齐路径。若 motion vector 没有覆盖动态物体,网络或 temporal stage 会从上一帧错误位置采样,桌面反射就会出现拖影。若 normal 在 normal map 和几何 normal 之间语义混乱,网络会在纹理边缘和几何边缘之间做出不稳定判断。

ML 推理还要进入工程预算。离线渲染可以接受较高推理成本和 tile 重叠,实时渲染需要控制 resolution、format、dispatch 次数、显存读写和与 upscaler 的顺序。一个 4K beauty 加上多张 float feature buffer 会带来明显内存带宽压力;推理本身也会占用 compute queue,并和后处理、TAA、upscaler 争抢 GPU 时间。

使用 ML denoiser 的稳定流程是:先用高采样 reference 建立目标质量;再固定输入 buffer 的色彩空间、动态范围和坐标空间;然后在代表性镜头上比较静态误差与动态误差;接着观察 feature ablation,即逐个移除 albedo、normal、depth、motion vector,确认每个输入实际支撑的细节;最后设置 fallback,在 unsupported device、显存不足或 feature 缺失时切换到较保守的 spatial denoiser。

在贯穿画面中,ML denoiser 对墙面和木桌漫反射区域收益最高;对玻璃杯折射、金属杯高光和桌面镜面反射,需要结合 firefly clamp、specular 分离、hit distance 或 temporal validation。网络可以改善重建,但输入语义错误会直接变成输出错误。

73.4 去噪与渲染管线的集成方式

去噪 pass 的位置取决于它要读取哪些数据以及输出给谁使用。离线路径通常在采样完成后对 beauty 和 AOV 做 denoise,再交给合成。实时路径通常在 ray tracing pass 后、tone mapping 前执行,并和 TAA、upscaler、motion blur、DOF、bloom 等后处理排序。排序错误会让 denoiser 读取到 display-referred 颜色、jitter 后坐标或已经合成的 UI,从而破坏重建假设。

贯穿画面的实时管线可以组织为:G-buffer pass 输出 depth、normal、albedo、roughness 和 motion vector;ray tracing pass 输出 noisy diffuse radiance、noisy specular radiance、hit distance 和 variance;denoising pass 读取这些资源并写入 denoised radiance;lighting combine pass 把 denoised radiance 与材质项合成;后续再进入 tone mapping 和显示输出。

这条路径可以用一个 frame graph 视角表示:

去噪器的输入要保持 scene-linear 语义。Path tracing 输出的 radiance 通常处在线性 HDR 空间,denoiser 应在 tone mapping 前处理。若先做曝光曲线或 gamma 编码,高亮 firefly 的能量关系会被压缩,网络或滤波器看到的分布会偏离训练或设计假设。若先合成 bloom,denoiser 会把后处理光晕当作真实光照扩散。

Feature buffer 要对齐到同一像素语义。Depth 应对应 denoiser 预期的空间,例如 linear viewZ 或 device depth;normal 应说明是 world space、view space 还是 encoded normal;motion vector 应说明单位是像素、NDC 还是 texture UV;albedo 应保持材质 base color,并处理透明和贴花合成规则。任何一个字段的空间或编码不一致,都会让边缘保护和历史重投影失效。

Tile inference 需要处理边界重叠。离线或高分辨率 ML denoising 常把图像切成 tile 推理。卷积网络或滤波器在 tile 边界需要邻域像素,直接无重叠切分会产生 seam。工程上要给每个 tile 增加 overlap,输出时只保留中心区域,或使用支持整图流式处理的推理路径。OIDN 文档中提到 tile 相关参数和 filter 创建成本,这类信息提示集成层应复用 filter 对象并减少重复初始化。

Temporal stability 依赖历史验证。实时 denoiser 从上一帧读取 history color 或 moments 时,要用 motion vector 回溯上一帧位置,再用 depth、normal、roughness 和 disocclusion mask 判断历史是否可信。相机移动时,墙面历史可大量复用;金属杯后新露出的背景缺少历史,应降低 history weight;桌面反射中的 specular 内容需要 hit distance 或反射 motion 参与判断。

资源状态和同步要显式进入设计。Vulkan、Direct3D 12 和 Metal 中,noisy radiance、feature buffer、history buffer 和输出 texture 都有读写状态。Denoising pass 通常是 compute dispatch,前序 ray tracing pass 写入 UAV 或 storage texture 后,需要 barrier 让后续 compute 读取可见;输出给 lighting combine 或 upscaler 前,也要切换到对应读取状态。OpenGL 或引擎封装可能隐藏部分同步,但 GPU 执行仍然遵守资源可见性和顺序约束。

下面是一段简化的伪代码,用来表达去噪集成层应该绑定哪些资源。它省略具体 API 调用,重点展示资源语义。

struct DenoiseInputs {
Texture noisyDiffuseRadiance;
Texture noisySpecularRadiance;
Texture albedo;
Texture normal;
Texture linearViewZ;
Texture roughness;
Texture motionVector;
Texture hitDistance;
Texture previousHistory;
};

struct DenoiseOutputs {
Texture denoisedDiffuseRadiance;
Texture denoisedSpecularRadiance;
Texture currentHistory;
};

void RunDenoisePass(CommandList& cmd, const DenoiseInputs& input, const DenoiseOutputs& output) {
cmd.BarrierForComputeRead(input.noisyDiffuseRadiance);
cmd.BarrierForComputeRead(input.noisySpecularRadiance);
cmd.BindDenoisePipeline();
cmd.BindSRV("NoisyDiffuse", input.noisyDiffuseRadiance);
cmd.BindSRV("NoisySpecular", input.noisySpecularRadiance);
cmd.BindSRV("Albedo", input.albedo);
cmd.BindSRV("Normal", input.normal);
cmd.BindSRV("ViewZ", input.linearViewZ);
cmd.BindSRV("Motion", input.motionVector);
cmd.BindUAV("DenoisedDiffuse", output.denoisedDiffuseRadiance);
cmd.BindUAV("DenoisedSpecular", output.denoisedSpecularRadiance);
cmd.Dispatch2D(input.noisyDiffuseRadiance.Width(), input.noisyDiffuseRadiance.Height());
cmd.BarrierForShaderRead(output.denoisedDiffuseRadiance);
cmd.BarrierForShaderRead(output.denoisedSpecularRadiance);
}

这段伪代码对应的判断点是:去噪 pass 属于资源密集型 compute stage,它的正确性来自输入语义一致、资源状态正确和历史 buffer 生命周期稳定。它的性能风险来自多张 full-resolution texture 读写、额外 history 存储、tile overlap、推理 dispatch 和同步等待。

Fallback path 要在设计初期确定。设备不支持目标 denoiser、显存预算不足、feature buffer 缺失、透明区域 guide 不可信、motion vector 错误时,管线应能切到较小半径滤波、只处理 diffuse、降低分辨率、跳过 specular temporal history 或提高采样数。Fallback 的目标是保持画面可预测,减少单个复杂区域破坏整帧稳定性。

73.5 质量评估指标与误差控制策略

去噪质量评估要同时看静态误差、动态误差和艺术可接受性。静态误差关注 denoised frame 与高采样 reference 的差异;动态误差关注相机移动、物体运动和光照变化中的 ghosting、boiling、lag;艺术评审关注材质意图是否被改变,例如金属高光是否变钝、皮革粗糙度是否被抹平、阴影是否过度扩张。

常用数值指标包括 MSE、PSNR、SSIM 和感知类指标。MSE 和 PSNR 对整体能量误差敏感,适合检查大面积偏色和曝光偏差;SSIM 更关注结构相似性,适合观察边缘和纹理保持;感知类指标更接近人眼评价,但训练数据和用途会影响解释。数值指标要和图像差分、局部放大、动态播放共同使用。

细节保留可以通过 feature 对齐来复查。地毯纹理在 albedo 中存在,denoised output 也应保留对应高频;墙面 albedo 平滑,output 中的随机颗粒应下降;桌面边缘的 normal 和 depth 有突变,output 不应跨边界混色。这个检查把“看起来干净”转成可复查的资源关系。

边缘漂移来自 guide 和 color 的不一致。比如 normal map 在地毯上产生高频法线变化,但 albedo 也有真实纹理,滤波器可能把两者都当作边缘保护信号,导致噪声残留。又如深度边界经过 TAA jitter 后与 noisy radiance 半像素错位,denoiser 会在物体边缘产生暗线或亮线。评估时应检查 feature buffer 是否与 beauty 同一分辨率、同一 jitter、同一采样位置。

Ghosting 是 temporal denoising 的主要动态错误。它表现为上一帧颜色在当前帧残留,常见于移动物体、反射变化、遮挡暴露和粒子/透明对象。排查 ghosting 的顺序是:先可视化 motion vector,再可视化 disocclusion mask,然后固定相机只动对象,接着固定对象只动相机,最后降低 history weight 观察残影是否消失。若残影随 history weight 改变,问题多半在历史复用路径;若残影仍在,问题可能来自 feature 对齐或后处理排序。

Bias 要用高采样 reference 评估。一个 denoiser 输出可能非常稳定,但把 caustics 压掉、把 specular lobe 扩宽、把阴影半影收窄。这些错误在单帧低采样输入中很难分辨,必须通过 reference 或更高 spp 的对照帧确认。对于最终帧渲染,可以用固定相机高采样图作为 reference;对于实时镜头,可以选取关键帧和慢速相机路径做 reference sweep。

Artist review 提供数值指标覆盖不到的约束。艺术目标可能要求保留特定噪声质感、锐利高光、局部纹理或风格化阴影。评审意见要落回可调参数,例如 firefly clamp 阈值、specular history weight、normal 权重、tile overlap、denoiser quality mode 或 samples per pixel。这样艺术反馈才能进入可复现的工程调参。

误差控制策略可以按优先级组织。第一层是采样端控制:改进 light sampling、MIS、sample sequence、firefly clamp 和 path termination,减少极端噪声输入。第二层是 feature 端控制:保证 albedo、normal、depth、motion vector、roughness 和 hit distance 的空间、编码和生命周期一致。第三层是 denoiser 端控制:调节 kernel、history weight、variance estimate、network quality、tile overlap 和 fallback。第四层是评估端控制:使用 reference、差分图、动态播放和艺术复查共同验收。

对贯穿画面而言,最终质量判断可以这样落地:墙面噪声应大幅下降且无色块;地毯纹理应跟 albedo 对齐且无随机闪烁;金属杯高光应保留能量集中感,同时 firefly 数量受控;玻璃杯区域允许采用更保守的滤波策略;桌面反射在相机移动时应减少拖影。这个结果同时绑定了视觉目标、输入资源、管线阶段和评估证据。

最小自检任务

给定一帧 2 spp 室内路径追踪画面,输入包括 noisy beauty、albedo、world normal、linear depth、roughness、motion vector 和上一帧 history。画面中有三个问题:墙面颗粒明显,地毯纹理被去噪后变糊,金属杯高光在镜头移动时留下残影。请设计一条排查顺序,说明每一步要看哪个 buffer、判断哪个管线阶段,以及可能的修正方向。

答案要点

先把问题分成空间噪声、细节损失和 temporal ghosting。墙面颗粒应先看 albedo、normal、depth 是否平滑,再看局部方差和滤波半径;若 guide 连续且颗粒随机,可以增加空间滤波强度或提高历史累积权重。地毯变糊要比较 output 与 albedo 高频是否对齐,再检查 normal 权重和 albedo 权重;若纹理在 albedo 中清楚存在,denoiser 的细节保护不足,应降低跨纹理混合或改进 feature 输入质量。金属杯残影要先可视化 motion vector,再检查 specular hit distance、roughness 和 history validation;若残影随 history weight 降低而消失,问题来自历史复用路径,应加强 disocclusion 判断、降低 specular history weight 或分离 diffuse/specular 去噪。整条排查要在 tone mapping 前的 scene-linear radiance 上完成,并用高采样 reference 或关键帧对照确认 bias。

本章知识点总结

  • 采样方差:Monte Carlo 像素估计的方差随样本数增加而下降,但标准差只按平方根速度收敛。
  • 噪声归因:去噪前应先区分采样误差、真实纹理、几何边界、材质高光和时间历史错误。
  • Firefly 来源:高能长尾样本来自小光源、镜面路径、caustics 或低概率高贡献路径,单纯模糊会扩散错误能量。
  • 传统滤波:Bilateral、A-trous 和方差引导滤波依赖局部相似性,适合 guide buffer 可信的不透明表面。
  • 滤波失败:透明、反射、体积、毛发和运动遮挡会削弱 depth、normal、albedo 的边界解释力。
  • ML 去噪:神经网络能联合 noisy beauty 与辅助 buffer 学习重建规则,但训练分布和输入语义会影响 bias。
  • 辅助特征:Albedo、normal、depth、roughness、motion vector 和 hit distance 分别支撑纹理保护、边界保护、遮挡判断和历史对齐。
  • 管线位置:去噪通常应处理 tone mapping 前的 scene-linear radiance,并在后处理、TAA 或 upscaler 前后保持清晰排序。
  • 资源同步:Denoising pass 需要明确 noisy radiance、feature buffer、history 和输出 texture 的读写状态与生命周期。
  • 时序稳定:Temporal denoising 依赖 motion vector、depth、normal 和 disocclusion mask 验证历史可信度。
  • 质量评估:MSE、PSNR、SSIM、差分图、动态播放和艺术复查应共同判断去噪结果。
  • 误差控制:稳定结果来自采样端、feature 端、denoiser 端和评估端的连续控制。