TSR(Temporal Super Resolution)是 UE5 默认的上采样方案:内部以低分辨率渲染(比如 1080p 渲染→4K 输出),靠历史帧累积把细节重建回来。它一半是抗锯齿(TAA 的职责),一半是上采样(TAAU 想做的事),但实现上比两者都激进。代码在 Engine/Source/Runtime/Renderer/Private/PostProcess/TemporalSuperResolution.cpp(UE5.3)。
问题设定:信息量从哪来
先看清楚输入输出的信息量。4K 输出有 830 万像素,1080p 输入只有 207 万——单帧信息不足以填满输出,必须有别的信息源。TSR 的信息源是时间:相邻帧之间相机和物体的亚像素抖动(jitter)让每个采样点落在输出像素网格的不同位置,把多帧的偏移采样拼起来,理论上能逼近甚至超过原生分辨率的有效信息。
用采样理论说:jitter 把每帧采样点散布在输出网格上,N 帧累积后有效采样密度提升 N 倍。重建滤波器要做的就是在无噪声的前提下把这些样本加权合成。TSR 的质量上限由历史帧数×每帧抖动覆盖度决定,而不是当前帧的分辨率——这也是它和单纯放大的本质区别:放大不增加信息,TSR 增加。
历史验证:TAA 的幽灵问题在超分下放大
时序重建的通用难题是历史像素是否还代表当前像素:物体动了、被挡了、光照变了,历史样本就是"幽灵"(ghosting)。普通 TAA 里幽灵是一块拖影;TSR 里由于输入输出分辨率差 4 倍,一个历史样本的错误贡献会被插值到 4 个输出像素,幽灵问题更严重。
TSR 的验证分两道:
- 深度/运动向量重投影。当前帧像素 $p$ 经运动向量回溯到上一帧位置 $p'$,取历史颜色。这是所有时序方案的标配;
- 颜色邻域钳制(neighborhood clamp)。在当前帧像素周围取 3×3 邻域,把历史颜色钳制到邻域颜色的 min-max 范围内(有实现用 AABB 加软边界而不是硬 min-max)。超出范围说明历史不可信,向当前帧颜色拉回。
TemporalSuperResolution.cpp里对应History Validation一组 pass。
普通 TAA 做完这两步基本够用,TSR 多做了一步:双向验证的可分离。超分场景下历史帧的角色是"高分辨率细节的来源",不是"去噪的 temporally累积"——所以 TSR 允许历史贡献超过传统 clamp 范围,但要用历史自身的置信度加权(历史帧在生成它的时候做了多少验证,置信度就存多少)。这让 TSR 在遮挡边缘比 TAA 更敢用历史,细节保留更好,代价是参数调错时闪爍(flickering)比 TAA 更难调。
与 TAAU 的差异:为什么 UE 要另起炉灶
TAAU(Temporal Anti-Aliasing Upsampling)在 UE4 后期就存在,思路一样(低分辨率累积+上采样),TSR 与之的差异值得专门说:
| 维度 | TAAU | TSR |
|---|---|---|
| 上采样比例 | 一般 ≤2× | 设计目标 2×,可更高 |
| 历史缓冲分辨率 | 输出分辨率 | 输出分辨率 |
| 重建滤波 | 固定核 | 自适应(按历史置信度) |
| 抖动序列 | 低分辨率网格内 | 输出分辨率网格(更细的抖动) |
| 去噪职责 | 依赖渲染端低噪输入 | 内置历史去噪,接受更噪的输入 |
关键在最后一行。TAAU 要求输入帧本身足够干净(SSAO、阴影等要先在低分辨率下收敛),否则上采样会把噪声也放大;TSR 把历史去噪纳入重建核,可以接受低分辨率下更激进的效果(更便宜的 SSAO、更少的阴影采样),把省下的预算让给主渲染。这是"上采样器吃掉整个渲染管线的去噪职责"的思路,也是 4K 输出配 1080p 渲染还能看的结构性原因。
实现要点:TSR 的 pass 链
TemporalSuperResolution 的 RDG 序列(简化):History Resample(从上一帧 TSR 输出按运动向量重采样)→ Reject/Clamp(邻域验证,生成每像素的历史置信度)→ Depth Repair(处理深度不连续处的历史失效)→ Filter(空间滤波压残余噪声)→ Update History(写回历史缓冲,供下帧用)。其中 Depth Repair 一步是 TAA 里没有的:TSR 的历史缓冲是输出分辨率的,历史像素和当前像素的深度对应关系在低分辨率输入下更容易错位,需要专门处理半遮挡边缘。
代价与调优
TSR 不是免费的午餐,账单在这几处:
- 渲染分辨率降 1/4,GPU 时间大约省 30-40%(不是所有 pass 都按像素计费,vertex 密集和固定开销不受影响);
- 显存增量:历史缓冲按输出分辨率存(颜色+置信度+深度),4K 下 ~100MB 级;
- 闪烁调优是主要维护成本:
r.TSR.*参数族里,History.Validation和History.GrandReprojection相关参数控制幽灵-细节的天平。闪得厉害先查运动向量是否正确(植被 WPO、皮肤骨骼的 motion vector 生成都容易漏),再动参数。
和 DLSS/FSR 的关系也值得说清:TSR 是引擎内的纯时序方案,不依赖专用硬件单元;DLSS 用 Tensor Core 跑网络超分,细节重建更敢猜(可能" hallucinate 细节")。UE5 项目里两者可共存(DLSS 插件替换 TSR 的输出端),选择依据是目标硬件分布和内容类型——植被密集内容 DLSS 占优,风格化/手绘内容 TSR 更不容易出鬼影。
源码入口
- 主入口:
TemporalSuperResolution.cpp的AddTemporalSuperResolutionPasses; - 历史验证逻辑:
FilterTemporal、RejectShadingHistory相关函数,重点看 clamp 用的邻域构造方式; - 参数文档:控制台
r.TSR.前缀全部参数,r.TSR.History.ScreenPercentage控制输入渲染比例(默认 50%,即 4K 输出配 1080p 渲染)。
TSR 的工程价值在于把"分辨率"从渲染预算的硬约束变成了可分配变量——同样的 GPU 时间,原生 4K 跑 30fps 还是 1080p 渲染 + TSR 跑 60fps,这个选择权在发行前都是开放的。理解它的信息论本质,才能在调优时不至于陷入参数盲调。