中EN
概念页

虚拟阴影贴图

Virtual Shadow Maps

更新于 2026-10-16 约 8 分钟UE5阴影虚拟阴影贴图VSMSMRT软阴影缓存

虚拟阴影贴图 (Virtual Shadow Maps, VSM) 是 UE5 默认的阴影方法:概念上就是分辨率极高(虚拟 16k×16k)的阴影贴图,切成 128×128 的页 (Page),只为屏幕上需要着色的像素分配和渲染页,并跨帧缓存;方向光用 clipmap 覆盖大范围,软阴影由阴影贴图光线追踪 (Shadow Map Ray Tracing, SMRT) 生成。它为 Nanite 设计,与 Nanite 一起使用时最高效。

原理:把阴影贴图"虚拟化"

传统 阴影贴图 的核心矛盾是分辨率:一张贴图要覆盖整个可见范围,近处像素不够用。级联阴影贴图 用几级级联缓解。VSM 的做法与 大场景渲染与虚拟纹理 中的虚拟纹理同构:(Virtual Shadow Maps)

  1. 每个光源拥有一张虚拟 16k×16k 的阴影贴图,切成 128×128 的页;
  2. 分析深度缓冲,标记"屏幕上着色确实需要"的页,只为这些页分配物理内存并渲染;
  3. 页跨帧缓存,除非被移动的物体或光源失效 (Invalidate)。

下图表示一帧的 VSM 流程:

flowchart LR
    A["深度缓冲"] --> B["页标记<br/>需要哪些页/哪级 mip"]
    B --> C{"页在缓存且未失效?"}
    C -- "是" --> D["复用缓存页"]
    C -- "否" --> E["渲染该页<br/>Nanite 一次/非 Nanite 逐光源绘制"]
    D --> F["物理页池"]
    E --> F
    F --> G["阴影投影 SMRT 采样"]

不同光源的组织方式:(Virtual Shadow Maps)

光源结构细节层次选择
方向光clipmap:每级一张 16K VSM,每级覆盖前一级两倍半径;默认第 6–22 级,即约 64 cm 到 40 km按到相机距离;r.Shadow.Virtual.ResolutionLodBiasDirectional,-1 使分辨率加倍
聚光灯一张 16k VSM + mip 链把屏幕像素大小投影到阴影空间选 mip
点光源立方体贴图,每面一张 16k VSM同上

clipmap 和级联本质上都是"按距离分级的分辨率",但 VSM 每级都是稀疏分配的虚拟贴图,空级几乎没有成本。(Virtual Shadow Maps) 选页级别的思路也和 细节层次 / mip 选择一致。官方也坦言:VSM 仍有透视走样 (Projective Aliasing)(光线几乎平行于表面时),"用阴影贴图解决透视走样没有简单方案"。(Virtual Shadow Maps)

VSM 启用后会取代:固定光源 (Stationary) 预计算阴影、预阴影 (Pre-shadow)、逐物体阴影、CSM 以及可移动局部光源的动态阴影;距离场阴影不被取代,可在动态阴影距离外为非 Nanite 几何接管;光追阴影仍优先。(Virtual Shadow Maps)

软阴影:SMRT

SMRT 向光源发出若干条光线,但不与几何求交,而是把沿光线的若干采样点投影到 VSM 上做测试,从而得到软阴影和接触硬化 (Contact Hardening)——遮挡体离接收面越远阴影越软。官方指出过去基于 PCF 的方法会均匀地过度模糊、削弱高分辨率几何的细节。(Virtual Shadow Maps) 这与 软阴影 PCF 与 PCSS 中 PCSS 追求的"按遮挡距离变化的半影"目标相同,只是实现换成了在阴影贴图上的光线步进。

  • 光线分布由局部光的 Source Radius 或方向光的 Source Angle 决定;Epic 级默认 8 条光线;r.Shadow.Virtual.SMRT.RayCountLocal/Directional 设为 0 则退化为单次采样硬阴影;每条光线采样数 4–8 效果较好。(Virtual Shadow Maps)
  • 局限:VSM 只存第一层深度,遮挡体重叠处会漏光,用"填缝启发式"外推;半影大小被钳制,Source Radius/Angle 过大会变形且变慢。(Virtual Shadow Maps)

缓存:性能的关键

官方说复用前几帧的页是保持高性能的关键。失效来源:(Virtual Shadow Maps)

  • 光源移动或旋转 → 该光源所有缓存页失效;
  • 投影几何移动、添加、删除 → 从光源视角看与其包围盒重叠的页失效(包括蓝图设置了属性导致渲染状态失效但实际未动的情况);
  • 使用 WPO(世界位置偏移)或 PDO(像素深度偏移)的材质、骨骼动画 → 每帧失效。

应对:

  • 用 Cached Page 可视化(绿=缓存,红=新/失效)和 ShadowCasters 视图找出元凶;包围盒要紧,宽松包围盒在低光照角度下会造成大量无谓失效。
  • 完全处于 Nanite 物体阴影中的失效可以跳过,非 Nanite 不行——所以建筑等大投影体应使用 Nanite(见 Nanite 虚拟化几何体)。
  • 按图元设置 Shadow Cache Invalidation Behavior(Auto/Always/Rigid/Static);用 World Position Offset Disable Distance 让远处植被停止摆动。
  • 静态/动态分离缓存:VSM 实际保存两份深度(静态与动态),动态物体移动时不必重画昂贵的静态几何;理想情况下静态页失效数接近 0,频繁失效的物体应改为 Movable。

性能分析

VSM 成本落在两个桶:(Virtual Shadow Maps)

桶内容主要影响因素调优
Shadow Depths把几何渲染进阴影页需渲染的页数 × 要渲染的几何量提高缓存命中;全面启用 Nanite;非 Nanite 配完整 LOD、r.Shadow.RadiusThreshold、远处切距离场阴影、关闭粗糙页中的非 Nanite
Shadow ProjectionSMRT 采样每像素平均光源数、每像素光线数、每光线采样数先减小 Source Radius/Angle,再降光线/采样数

非 Nanite 几何渲染进 VSM 要贵得多:方向光一次 Nanite 通道画完所有方向光,非 Nanite 则每个光源一个通道、逐物体绘制调用;一个静态网格实例对点光源可能变成 48 个剔除实例(8 级 mip × 6 面),对方向光 17 个(17 级 clipmap)。(Virtual Shadow Maps) 统计用 r.ShaderPrintEnable 1 + r.Shadow.Virtual.Stats 1,也可在 Unreal Insights 中 trace.enable counters,vsm;测量时用 r.RDG.AsyncCompute 0 获得更有代表性的分通道时间(仅限分析,切勿用于发行)。(Virtual Shadow Maps) 详见 UE5 性能分析。

坑与限制

  • 低多边形高曲率模型出现"阴影明暗交界线问题 (Shadow Terminator)":首选加面(Nanite 加面便宜),实在不行再调 r.Shadow.Virtual.NormalBias(默认 0.5),后者会损失全场景细节。(Virtual Shadow Maps)
  • 物理页池溢出会导致棋盘格或阴影缺失,需调 r.Shadow.Virtual.MaxPhysicalPages 或降分辨率/光源数。(Virtual Shadow Maps)
  • 大量小局部光源的性能仍在改进中;Subsurface Profile 与透射尚未支持。(Virtual Shadow Maps)
  • 不用 Nanite 的项目或平台,VSM "很可能不合适";平台需要 DX12 SM6.6 原子操作或 Vulkan 64 位原子。(Virtual Shadow Maps)

阴影基础概念(自阴影、偏移、走样)见 阴影基础与阴影体。

  1. Virtual Shadow Maps UE 5.8 文档
  2. Nanite Virtualized Geometry Overview UE 5.8 文档

相关页面

图形学阴影贴图Shadow Mapping阴影贴图 (Williams, 1978) 先从光源位置渲染深度,再从相机渲染时把每个点到光源的距离与贴图中存的深度比较:更远就在阴影中。它开销可预测(生成约与图元数成线性、查询为常数时间),非常适合 GPU,是任意表面阴影最常用的算法。主要问题是分辨率、深度精度带来的混叠、阴影痤疮和漏光。图形学级联阴影贴图Cascaded Shadow Maps级联阴影贴图 (CSM) 把视锥沿视线方向切成几段,每段用一张紧贴它的阴影贴图,使近处获得更多阴影纹素。它实现简单、能覆盖巨大场景、没有严重的最坏情况,因此被大量应用。关键问题是深度如何划分、近平面放在哪里、怎样避免抖动和级联边界的质量突变,以及如何降低多张贴图的开销。图形学软阴影 PCF 与 PCSSSoft Shadows with PCF & PCSS百分比渐近过滤 (PCF) 在阴影贴图上取多个样本,分别与表面深度比较后混合结果,得到伪软阴影,但半影宽度恒定。PCSS 先搜索附近遮挡体的平均深度,再据此决定过滤宽度,从而在接触处硬、远处软(接触硬化)。图形学阴影基础与阴影体Shadow Basics & Shadow Volumes阴影帮助玩家判断物体的位置。精确光源只产生硬阴影,面光源产生带本影和半影的软阴影。最简单的情况是投射到平面上的投影阴影;投影纹理可把阴影扩展到曲面;阴影体用模板缓冲计数,能在任意表面得到精确硬阴影,但开销极不稳定,如今很少使用。图形学大场景渲染与虚拟纹理Large Scenes & Virtual Texturing当场景数据远大于内存(如主机只有 8 GB,而游戏世界有数百 GB)时,需要按需把数据流送进内存。本页讲三类技术:虚拟纹理(把巨大的 mipmap 链切成瓦片,只让可见瓦片驻留在显存,通过页表/间接纹理寻址)、纹理转码(磁盘上用高压缩比的可变码率格式,加载时转成 GPU 块压缩格式),以及按平面瓦片组织资产的通用流送。这些方法几乎总是与剔除和 LOD 配合使用;地形部分见 地形渲染。图形学细节层次Level of Detail细节层次 (LOD) 在物体对图像贡献变小时改用更简单的表示。LOD 系统由三部分组成:生成(简化或手工制作多个版本)、选择(按距离、投影面积等收益函数挑选)、切换(尽量减少跳变 popping)。LOD 主要减少顶点处理,也通过减少 quad 过度着色降低像素开销;进一步还可在预算约束下全局选择 LOD,实现时间关键(恒定帧率)渲染。图形学剔除技术Culling Techniques剔除 (culling) 是在渲染前尽快去掉对最终图像没有贡献的部分。本页讲几何类剔除:背面剔除(含成簇背面剔除与法线锥)、视锥剔除(层次化、平面掩码)、室内场景的入口剔除,以及牺牲质量换速度的细节剔除和小三角形剔除。更复杂的遮挡剔除见 遮挡剔除。游戏开发 · UE5Nanite 虚拟化几何体Nanite Virtualized GeometryNanite 是 UE5 的虚拟化几何体 (Virtualized Geometry) 系统:导入时把网格切成分层的三角形簇 (Cluster),渲染时按相机视角逐簇选择细节层次并无缝拼接,按需从磁盘流送,并在绕过传统绘制调用 (Draw Call) 的独立通道中渲染,使帧预算不再受多边形数、绘制调用和网格内存约束。游戏开发 · UE5Lumen 全局光照与反射Lumen Global Illumination & ReflectionsLumen 是 UE5 默认的全动态全局光照 (Global Illumination, GI) 与反射系统:先做屏幕空间追踪,未命中再对"Lumen 场景"做软件光追(有符号距离场)或硬件光追,命中点的光照从按网格离线放置的卡片 (Card) 构成的表面缓存 (Surface Cache) 中查询,表面缓存的直接与间接光照分摊到多帧更新,从而得到无限次漫反射弹射和全粗糙度范围的反射。游戏开发 · UE5UE5 渲染架构UE5 Rendering ArchitectureUE5 的渲染器是独立的 Renderer 模块,在渲染线程 (Rendering Thread) 上以「场景代理」镜像游戏线程的组件状态,每帧按固定顺序执行深度预通道、G-buffer 基础通道、光照、雾、半透明和后处理。现代渲染代码用渲染依赖图 (Render Dependency Graph, RDG) 声明通道与资源,由 RDG 自动排屏障、复用瞬态内存、并行录制;最终命令经 RHI 线程翻译成 D3D12/Vulkan 等图形 API 调用。默认走延迟着色 (Deferred Shading),也可切换前向着色 (Forward Shading)。游戏开发 · UE5UE5 性能分析UE5 ProfilingUE5 性能分析的基本流程是:先用 stat unit 判断瓶颈在游戏线程、渲染线程还是 GPU,再用对应的 stat 组、profilegpu/GPU 统计或 Unreal Insights 的 Timing/Memory 等视图向下钻取;渲染特性(RDG、VSM、TSR)各自提供作用域和可视化。测量时要避开会扭曲数据的设置(调试构建、异步计算、可视化模式)。综合帧时间预算与渲染性能Frame Budget & Rendering Performance本页把 wiki 中分散在 RTR4 第 18~23 章的性能知识串成一条线:一帧的时间预算由最慢的管线阶段决定,先用毫秒帧时间度量并定位瓶颈,再按瓶颈所在位置——CPU/驱动、几何、像素、带宽/内存——选用对应手段;最后从 GPU 硬件机制(占用率、HiZ/early-z、压缩、分块架构)理解这些手段为何有效。各结论的细节与出处见所链接的概念页。游戏开发脏标记Dirty Flag脏标记 (Dirty Flag) 用一个布尔标记记录“派生数据是否已经过时”:原始数据变化时置位;需要派生数据时,如果标记已置位就重新计算并清除标记,否则直接用缓存的结果。场景图里由局部变换求世界变换是经典例子。它只在原始数据变化比派生数据被使用更频繁、而且难以增量更新时才划算,最大的风险是漏置标记导致使用过时数据。游戏美术阴影的真实感要素Photoreal Shadow EssentialsDinur Ch8:阴影没有神秘「种类」,但制作上要抓住软硬(本影/半影)、影色、重叠与嵌套、接触/邻近影。本页补 Birn「影的构图功能与 cheat」与图形学阴影算法之间的外观检查清单。

输入关键词开始搜索

滚轮或双指缩放 · 拖动平移 · 双击放大 / 还原