← ALL ARTICLES
光线追踪4 MIN READ

光追降噪

全库目录221
本文目录13

原始光追噪声只有颜色,滤波不知道相邻样本是否来自同一表面。降噪加入深度、法线、粗糙度与命中距离,再决定历史与邻域能否复用。拒绝太松产生拖影,太严则保留噪声,诊断要看具体拒绝原因。

时空滤波

几何辅助缓冲

原始辐亮度只有颜色,很难判断两个相邻样本是否属于同一表面。降噪器常使用:

  • Linear 深度;
  • World/视图法线;
  • 粗糙度;
  • 材质/实例ID;
  • 运动向量;
  • 命中距离;
  • 样本数、方差、置信度。

辅助缓冲必须与射线结果来自同一几何和相机时刻。错误运动向量或不同法线空间会造成比噪声更明显的拖影。

时域积累

上一帧结果通过运动向量重投影到当前像素:

uprev=ucurr+vmotion\mathbf{u}_{prev}=\mathbf{u}_{curr}+\mathbf{v}_{motion}

若历史有效,则:

Ct=(1−α)Chistory+αCcurrentC_t=(1-\alpha)C_{history}+\alpha C_{current}

稳定区域使用小 α\alpha 积累更多样本;运动、光照变化或高方差区域提高 α\alpha,快速响应当前帧。

若历史已有3个等权样本、均值2,当前样本为6,历史权重3/4,结果为3。这个递推保留四个样本的算术平均;设最大历史权重后则成为有限响应的指数平滑,sampleCount不再直接表示独立有效样本数。遮挡揭露时权重归零,输出当前6,避免旧表面的2进入新表面。

遮挡揭露与历史拒绝

重投影位置存在历史像素,不代表历史属于当前表面。需要比较:

  • 深度/世界位置;
  • 法线;
  • 材质/实例ID;
  • 粗糙度;
  • 命中距离;
  • 对象/光照状态变化。

镜面反射的运动不能只用主表面运动向量。反射内容来自次级命中,镜头和反射面运动会产生复杂 Parallax。实时方案常依赖更严格的 Reject、较短历史和空间补偿。

时域积累的读取与拒绝

当前像素通过运动向量回投到上一帧。深度、法线和对象 ID 共同决定历史是否仍属于同一表面:

hlsl
float2 historyUv = uv + motionVector;
History h = ZeroHistory();
bool valid = all(historyUv >= 0.0) && all(historyUv <= 1.0);
if (valid) h = LoadHistory(historyUv);
valid = valid
          && abs(h.linearDepth - currentDepthInPreviousView) < depthThreshold
          && dot(h.normalWS, normalWS) > normalThreshold
          && h.objectId == objectId
          && all(isfinite(h.radiance)) && all(isfinite(h.normalWS))
          && isfinite(h.linearDepth) && isfinite(h.sampleCount)
          && h.sampleCount >= 0.0;
float3 accumulated = currentRadiance;
if (valid) {
    float historyWeight = min(h.sampleCount / (h.sampleCount + 1.0), maxHistory);
    accumulated = lerp(currentRadiance, ClampHistory(h.radiance), historyWeight);
}

调用者提供有限的当前颜色、可比深度、法线、非负深度阈值以及[0,1)内的maxHistory。先检查回投UV,再读取历史资源;拒绝历史时直接保留当前颜色,避免零权重乘NaN仍污染结果。有限但负的历史计数也按损坏记录拒绝。深度比较也要使用可比的相机空间:相机移动时,当前观察深度不能直接与前帧观察深度相减,可以把当前世界位置变到前帧视空间后比较。运动向量方向与回投公式保持一致。拒绝过严会重新出现噪声,过松会产生拖影。用静止相机、快速横移、遮挡显露和发光物突变四组场景分别检查收敛、遮挡揭露与历史限制范围。

历史限制范围

错误历史会产生拖影。常在当前邻域计算最小值和最大值或 Mean/方差,把历史颜色限制到可信范围。

方差 Clipping 可写为:

Chistory′=clamp⁡(Chistory,μ−kσ,μ+kσ)C_{history}'=\operatorname{clamp}(C_{history},\mu-k\sigma,\mu+k\sigma)

μ\mu 和 σ\sigma 来自当前邻域。kk 小会过度抹平,kk 大则残留历史 Ghosting。

HDR Firefly 会污染 Mean/方差。可先在 Luminance 或压缩颜色空间处理,并使用 Robust Statistics。

空间滤波

Cross-bilateral Filter 同时考虑屏幕距离、深度、法线、颜色和材质:

w=wp wz wn wcw=w_p\,w_z\,w_n\,w_c

例如中心亮度1,左邻居同表面亮度3且权重1,右邻居来自背景亮度100、深度权重0,归一化结果为(1+3)/2=2。若忽略深度门限就会得到104/3,轮廓出现漏光;若权重和没有归一化,改变有效邻居数量本身也会改变亮度。

A-trous Wavelet 每轮扩大采样 Step,不必降采样就能快速扩大感受野。迭代太多会丢高频阴影和反射细节。

Specular Filter Radius 应与粗糙度、命中距离和射线锥相关。镜面反射不能像 Diffuse GI 一样大范围模糊。

方差与自适应采样

可用一阶矩 E[x]E[x] 和二阶矩 E[x2]E[x^2] 估计:

Var⁡(x)=E[x2]−E[x]2\operatorname{Var}(x)=E[x^2]-E[x]^2

高方差区域可以增加空间过滤、降低历史信任,或在预算允许时分配更多射线。方差自身也有噪声,需要时间积累与数值保护。

降噪器常见伪影

  • Ghosting:历史没有及时 Reject;
  • Boiling:随机噪声在时间上持续变化;
  • Blurring:空间 Filter 跨越细节或半径过大;
  • 光源 Leak:深度/法线 Gate 太宽;
  • Dark Halo:遮挡揭露没有足够新样本;
  • Firefly Trail:极亮样本进入历史;
  • 反射 Lag:反射运动与主表面 Motion 不一致。

处理时先输出历史 Valid、样本数、方差、命中距离与 Filter Weight,不要只看最终颜色猜原因。

与 TAA/Upscaler 的关系

射线降噪器和 TAA/Upscaler 都使用时域信息,但负责的信号不同。降噪器应尽量输出稳定的光照信号;Upscaler 再处理最终画面的分辨率重建和抗锯齿。

两者连续积累会放大拖影。需要明确执行顺序、Jitter、运动向量、Exposure 和 Reactive 遮罩,不应把“后面还有 TAA”当作降噪器可以省略的理由。

历史裁剪与空间滤波分别改变信号。邻域均值和方差最好在约定的亮度或颜色空间计算,并使用与历史相同的曝光尺度;曝光翻倍而历史没重标定时,即使表面完全静止,也会被当成异常颜色。下方 ClampHistory 表示前述 μ±kσ\mu\pm k\sigma 的分量裁剪,当前帧邻域、参数 k 和色彩空间由调用者提供,不是任意黑盒修复。

验证方法

保留原始、只时域、只空间与最终结果,记录历史长度、方差和Reject Reason。深度比较先转到前帧可比空间,越界UV先拒绝再读历史。镜面次级运动与主表面速度分开核对。

正文抽取检查将相同控制流与算术编译为C++17 CPU宿主,检查正常四样本均值3、无效NaN历史、负计数和越界不读取;向量与资源读取由宿主替代,完整HLSL管线与GPU画面未运行。

相关主题

参考资料