UE 知识卡片
Rendering
Nanite · VSM · SMRT
Virtual Shadow Maps
UE5 下一代阴影:页面化流送、与 Nanite 协同,以及真实项目里的性能陷阱与诊断路径。
Question
请详细解释 Virtual Shadow Maps(VSMs)的核心机制、它们与 Nanite 的内在关系,以及如何实现一致的高分辨率阴影。同时讨论常见性能陷阱(非 Nanite 几何、快速相机运动、复杂材质),并说明如何在底层诊断与缓解——引用相关控制台变量与 C++ 考量。
一句话结论
VSMs 把阴影贴图像 Nanite 一样「虚拟化」:超高分辨率阴影被切成可缓存的页面,按屏幕需求按需分配与失效,从而在开放世界动态光照下仍能保持一致的高分辨率阴影。
虚拟分辨率概念上可达 16k×16k,定向光再用 clipmap 扩展
页面大小128×128 像素瓦片,按需分配 / 跨帧缓存
柔和阴影SMRT:接触硬化半影,非均匀模糊
最佳拍档Nanite 几何路径成本最低、质量最稳
核心机制
VSMs 在概念上是超高分辨率阴影贴图。为避免全量渲染,它采用基于页面的流送:
- 根据深度缓冲分析,只分配屏幕着色真正需要的页面;
- 页面跨帧缓存;物体或光源移动时才失效并重绘;
- 定向光通过 clipmap 在不同距离层维持合适解析度。
设计直觉:不是「永远画一张巨图」,而是「只画当前帧用得到的阴影碎片,并尽量复用」。
与 Nanite 的关系
VSMs 把 Nanite 的虚拟化思路延伸到阴影。Nanite 的自动 LOD / 剔除与 VSM 的页面分配天然契合:Nanite 能高效提供栅格化虚拟页面所需的高细节几何。
启用 VSMs 后,许多传统路径会被统一替换(Stationary 预计算阴影、逐对象阴影、可移动光的 CSM 等),因为 Nanite 往往不兼容这些旧技术。
柔和阴影:SMRT
VSMs 通过 Shadow Map Ray Tracing(SMRT) 做接触硬化半影:近处更锐、远处更软,比均匀 PCF 更符合物理。柔和度受光源半径/角度影响,也可由 CVar 控制采样数。
r.Shadow.Virtual.SMRT.SamplesPerRay.Local
r.Shadow.Virtual.SMRT.SamplesPerRay.Directional
常见性能陷阱
| 场景 | 为什么疼 | 优先动作 |
|---|---|---|
| 非 Nanite 几何 | 走更贵的栅格化路径,相机移动时易尖峰 / 伪影 | 能 Nanite 就 Nanite;否则评估是否必须投 VSM |
| 快速相机 / 大面积露出 | 大量页面在同一帧失效、分配、重绘 | 降分辨率与物理页上限;减少动态投射物 |
| 复杂材质 | WPO、Masked、可编程栅格化抬高深度通道成本 | 简化投射阴影材质;必要时换阴影方案 |
| VRAM 压力 | 物理页面池仍占显存,高 clipmap / 多光源更糟 | 调 MaxPhysicalPages、clipmap 最大分辨率 |
诊断
Unreal Insights/stat gpu/profilegpu:盯Shadow Depths,尤其是Render Virtual Shadow Maps Non-Nanite- 编辑器可视化:
Show → Visualize → Virtual Shadow Maps(页面分配、失效、非 Nanite 贡献)
缓解策略
- 优先 Nanite:静态与高模动态网格尽量开 Nanite。蒙皮 / 复杂 WPO 无法 Nanite 时,评估胶囊体阴影或预计算阴影。
- 调质量档:用下表 CVar 按预算下调分辨率、页面池、SMRT 采样。
- 简化投射材质:去掉不必要的 WPO / 复杂 Masked / 自定义可编程栅格化。
- 管动态:减少高频移动的 VSM 投射物与高质可移动光数量。
- 借 World Partition:减少任一时刻需要考虑的潜在阴影投射物总量。
CVar 速查
| 控制台变量 | 用途 |
|---|---|
r.Shadow.Virtual.Enable 0 | 最后手段:整站关掉 VSM |
r.Shadow.Virtual.ResolutionLodBiasDirectional | 定向光整体分辨率偏置(约 -3~3,降低可减负载) |
r.Shadow.Virtual.Clipmap.MaxResolution | 定向光 clipmap 最大分辨率(如 2048) |
r.Shadow.Virtual.MaxPhysicalPages | 物理页面上限(过低会伪影) |
r.Shadow.Virtual.SMRT.SamplesPerRay.* | 柔和阴影采样(1–8);降采样换性能 |
注意:把
MaxPhysicalPages 压太低会直接出阴影破洞 / 闪烁。先用可视化确认是「分配过多」还是「失效风暴」。
C++ 考量(进阶)
- 对问题 Actor 关闭阴影 / VSM:
UPrimitiveComponent::SetCastShadow(false),或SetCastVirtualShadowMap(false)(若已暴露) - 按场景动态改 VSM CVar / 光源设置(例如动作镜头临时降质)
- 极端情况再下钻引擎源码:
Engine/Source/Runtime/Renderer/Private/VirtualShadowMaps/