UE5 Graphics Deep Insights From Japan

UE5 Graphics Deep Insights From Japan | Unreal Fest Bali 2025

引言:UE在日本的应用

  • 核心观点: Unreal Engine在日本不仅用于传统的写实风格游戏 (如《最终幻想7》、《王国之心》),也广泛用于非真实感渲染 (NPR) 风格的作品。

  • 日本市场特性:

    • 偏好风格化: 受到漫画和动画的启发,风格化图形非常流行。

    • 主流平台: 主要是游戏主机 (特别是 SwitchPlayStation),而非PC或移动设备。

    • 开发需求: 这意味着严格的性能优化是刚需。


一、 GPU性能分析 (GPU Profiling)

ProfileGPU 的准确性问题

演讲的核心问题:ProfileGPU 命令在多大程度上能准确反映真实的GPU工作负载?

答案是:不一定准确,主要干扰因素是异步计算 (Async Compute)

异步计算 (Async Compute) 带来的挑战

  • UE5的趋势: UE5越来越多地使用异步计算(例如Lumen)来并行处理图形管线和计算管线,以提高GPU的利用率和效率。

  • 分析的困难:

    1. 任务重叠: 异步计算导致多个渲染过程在时间上重叠。这使得在分析器中很难孤立地查看单个任务的GPU工作负载

    2. 隐藏的等待: 某个Pass(如Lumen Scene Lighting)在分析器上可能显示占用了2毫秒,但实际上其中包含了很多GPU等待时间,并非纯粹的计算开销。

UE中分析工具的演进 (5.6版本为分水岭)

1. Unreal Insights (UE Insights)

  • UE 5.5及之前: 无法显示异步计算任务。例如,Lumen中重要的ScreenProbe Pass在Insights中是不可见的。

  • UE 5.6及之后: 默认支持显示计算管线 (Compute Pipe),无需额外设置。

2. ProfileGPU 命令

  • UE 5.5及之前:

    • 为了测量,它会强制关闭异步计算

    • 这导致其结果不准确,因为它没有体现异步计算带来的性能优势,测得的开销可能高于实际运行情况

  • UE 5.6:

    • ProfileGPU 开始支持异步计算,结果会同时显示图形和计算管线。

    • 但专用的UI窗口被移除,结果只显示在输出日志 (Output Log) 中。

  • UE 5.7:

    • ProfileGPU 的UI窗口回归。

    • 重要注意: 此版本不会禁用异步计算(因此总时间更准),但它不会显示计算管线的活动详情

性能分析工具的正确使用层级

讲者强调,不应只依赖UE内置工具。

  1. UE内置工具 (ProfileGPU, Unreal Insights)

    • 用途: 适用于日常分析,快速了解性能瓶颈在哪里 (Where)。

    • 优点: 轻量级,易于使用。Unreal Insights 是获取完整管线图(图形+计算)的首选。

  2. 平台/硬件方分析器 (PIX, Razor, NSight等)

    • 用途: 深入理解为什么某个Pass开销很高 (Why)。

    • 优点: 可以捕获单帧,详细分析是计算密集、纹理访问过多、寄存器使用率高,还是异步计算重叠问题。

    • 结论: 使用这些工具可以避免进行无效或不必要的优化

核心洞察:如何正确进行GPU分析

  • 异步计算使分析更难: 由于任务重叠,理解单个Pass的开销变得更加困难。

  • UE 5.6是转折点: 此版本后,UE的工具才开始原生支持异步计算的可视化。

  • 隔离Pass的方法: 如果你想微调和优化某个特定的渲染过程(如Lumen),建议在分析时暂时禁用该过程的异步计算,以便观察其独立的开销。

  • 工具组合拳:

    • 日常使用 Unreal Insights 查看整体负载和瓶颈分布。

    • 深入分析使用平台方工具 (PIX, NSight等) 来定位开销的根本原因


二、 着色器复杂度视图 (Shader Complexity View Mode)

核心误区:指令数量 ≠ 性能开销

  • 视图功能: Shader Complexity 视图的目的是可视化每个像素执行的着色器指令总数

  • 核心问题: 在此视图中显示为红色(昂贵)或白色(极度昂贵)的材质,是否_一定_需要修复?

  • 答案:否。 讲者强调:指令数量 (Instruction Count) 绝对不等于性能开销 (Performance Cost)。

  • 经典类比:

    • 请求1:“给我做点煎饼。”

    • 请求2:“在GDC上做两个技术演讲。”

    • 两个请求写下来都只是一行字(指令数少),但实际工作量(性能开销) 天差地别。

  • 材质中的同理:

    • 不同的指令开销不同(例如,纹理访问通常比简单的数学计算昂贵得多)。

    • 你可以在材质编辑器的 平台统计 (Platform Stats) 窗口查看指令数。

误导性的"陷阱"

陷阱1:智能的着色器编译器 (Alpha Test 示例)

  • Alpha Test (Masked Material): 材质中可能包含一个 discard 指令。

  • 编译器优化: 现代GPU编译器非常智能。它可能会首先评估Alpha条件,如果一个像素被 discard,后续所有其他计算(即使指令数很多)都将被跳过

  • 导致的结果: 一个材质可能指令总数非常高,但在 Shader Complexity 视图中看起来很昂贵,而实际GPU开销却极低,因为大部分指令都被跳过了。

“魔鬼”示例:

  1. 低指令数 (39),高开销 (20ms):一个故意构造的材质,可能涉及复杂的依赖或纹理读取。

  2. 高指令数 (2533),低开销 (0.04ms):一个包含大量分支或discard的材质,大部分计算被跳过。

陷阱2:视图无法反映 Masked 材质的真实开销

  • 最大的问题: Shader Complexity 视图完全不反映被 discard (裁剪) 掉的透明区域的开销

  • Masked Material (遮罩材质): 即使是透明区域,GPU仍然运行了着色器(至少运行到 discard 指令)。这部分是有开销的。

  • 视图的误导: 该视图会将 Masked 材质显示得如同完全不透明 (Opaque) 材质一样廉价,这是严重误导

核心洞察:如何正确优化材质

  • Shader Complexity 的推荐用途: 讲者认为,这个视图现在最适合的用途可能只剩下检查半透明 (Translucent) 元素的重叠 (Overlapping) 情况。

  • 最危险的事: 投入时间去做无效的优化 (ineffective optimizations)。仅仅因为视图是红/白色就去削减指令数,很可能在牺牲了视觉质量后,并不能带来任何实际的性能提升。

  • 正确的优化路径:

    1. 使用详细的GPU分析器 (PIX, NSight等)。

    2. 精确定位真正的性能瓶颈(例如,是ALU计算受限,还是纹理读取或带宽受限)。

    3. 基于实际瓶颈进行优化。

三、 TSR (Temporal Super Resolution - 时间超分辨率)

TSR的核心价值与挑战

  • 核心价值: TSR是一种升采样 (Upscaling) 技术。它能以极低的性能开销(例如从57ms降至16ms)将低分辨率渲染(如1080p)提升至高分辨率(如4K),而视觉差异很小。

  • 对UE5的意义: NaniteLumen 的性能都依赖于内部渲染分辨率。TSR能极大地降低它们的负载。

  • 工作原理: TSR通过引用过去的多个帧来重建("收集样本")当前帧,以达到目标分辨率。

TSR的"阿喀琉斯之踵":Ghosting (鬼影)

TSR的质量高度依赖于能否从足够近的过去帧中收集到足够的样本。当它被迫引用_太久远_的帧时,就会出现鬼影。

导致引用过往旧帧的两个主要原因:

  1. 过低的内部渲染分辨率:

    • 原理: 内部渲染分辨率越低,TSR需要“拼凑”的像素就越多,因此需要回溯的帧数也越多。

    • 极端示例: 当内部仅以25%分辨率渲染时,摄像机移动会导致整个画面非常模糊

  2. 过低的帧率 (FPS):

    • 原理: 假设TSR需要引用4帧前的样本。

      • 60 FPS 下,这4帧发生在 ~66ms 内。

      • 30 FPS 下,这4帧发生在 ~133ms 内。

    • 结论: 帧率降低一倍,TSR就必须引用时间上“老”一倍的帧。这就是为什么帧率下降会导致鬼影。

    • CPU与GPU的共同责任: 即使GPU成本很低,但如果CPU成为瓶颈(例如动画、加载)导致FPS下降,同样会引发TSR鬼影

TSR的另一个关键:速度向量 (Velocity Vectors)

  • TSR的依赖: TSR使用速度向量来预测前一帧的像素在当前帧的位置。

  • 问题: 如果一个物体(例如一个旋转的轮子)没有被正确地写入速度向量,TSR就无法正确地"重投影"它的历史信息。

  • 结果: 在该物体上出现严重的模糊和鬼影

  • 解决方案: 必须确保所有运动物体(包括通过WPO或着色器实现的运动)都生成了正确的速度向量。

核心洞察:如何用好TSR

  • TSR的优点:摄像机静止时,TSR表现极佳。由于前后帧完全一致,它甚至能从25%的分辨率完美重建出高清图像。

  • TSR的敌人:

    1. 过低的内部渲染分辨率

    2. 不稳定的帧率(无论是GPU还是CPU引起的)。

    3. 错误的速度向量

  • 重要资源:UE 5.4 开始,TSR的官方文档得到了极大扩展,内容详尽,强烈推荐阅读。


四、 MegaLights (实验性功能)

  • 核心概念: 一项正在开发中的实验性 (Experimental) 新功能,旨在高效支持海量的光源,即使在主机平台上。

  • 工作原理: 它通过固定每像素每帧的最大采样数来实现。

  • 关键优势: 即使场景中的光源数量增加,处理成本也不会显著增加

  • 与传统渲染的对比:

    • 传统光照: 为每个光源执行光照计算。成本随光源数量线性增长,优先保证准确性

    • MegaLights: 优先保证性能优化。即使放置再多光源,开销也不变,但这可能会导致轻微的渲染错误或瑕疵

核心洞察:关于MegaLights的警告

  • 状态: 纯粹的实验性功能。

  • 讲者建议: 讲者非常严肃地建议,在"实验性"标签被移除之前,不要在任何生产项目中使用MegaLights


五、 虚拟纹理 (VT) 与 虚拟阴影贴图 (VSM)

1. 虚拟纹理 (Virtual Textures)

  • 重要变更:UE 5.6 开始,虚拟纹理默认开启

  • 核心问题: Moiré (摩尔纹) / 远处闪烁

    • 根本原因: 虚拟纹理有一个最小MipMap尺寸,即其Tile Size (图块大小,默认为 128x128)

    • 后果: VT不会生成比 128x128 更小的MipMap。当一个高频纹理被拉到很远时,由于缺乏足够小的Mip,会导致严重的摩尔纹和闪烁

    • 当前限制: 这是VT目前的固有局限。

  • 部分缓解方案:

    • TSR的一个控制台变量 r.TSR.Shading.Rejection.Flickering (在高/电影级设置下默认开启)可以极大改善这个问题。

    • 但这并非完美的解决方案,某些摄像机角度下摩尔纹仍可能出现。

2. 虚拟阴影贴图 (Virtual Shadow Maps - VSM)

  • 常见痛点: 开发者经常因为VSM的默认显存池 (512MB) 和高GPU负载而放弃使用它。

  • 重要更新: VSM的显存和性能在近期版本中已显著改善

优化技巧 1: 动态页面LOD (UE 5.4)

  • 功能: 允许VSM根据你设置的显存池大小自动动态调整页面的LOD

  • CVAR: r.Shadow.Virtual.MaxPagePoolLoadFactor

  • 示例: 即便将显存池从512MB强制降至60MB,VSM也能通过自动提升Page LOD(降低远处阴影质量)来适应这个预算,并依然渲染出效果不错的阴影

优化技巧 2: 动态负载调整 (UE 5.6)

  • 功能: 引入了一项新功能,可以根据实时性能表现动态降低VSM的处理负载,类似于动态分辨率。

核心洞察:VSM/VT总结

  • VT: 默认已开启(5.6+),但要警惕它因最小Mip限制 (128x128) 导致的远处摩尔纹

  • VSM: 性能和显存已大为改善(5.4+)。如果你曾因显存占用过高而放弃它,请尝试调小显存池并配合使用 MaxPagePoolLoadFactor

六、 Lumen (动态全局光照)

Lumen的优缺点

  • 优点:

    • 实时动态GI: 无需烘焙光照,允许在运行时实现动态光照。

    • 节省时间: 极大减少了光照烘焙的工作流程和时间成本。

  • 缺点:

    • 时间性瑕疵 (Temporal Artifacts): 和TSR类似,Lumen在运行时需要累积多帧的信息,这可能导致鬼影 (Ghosting) 或拖尾。

    • 性能开销: 性能开销相对较高(尽管在持续改进中)。

核心问题:模块化资产 vs. Lumen卡片 (Modular Assets vs. Lumen Cards)

这是讲者在日本支持开发者时遇到的最大问题,尤其是在使用Megascans或Fab导入的模块化资产时。

1. 关键概念定义

  • 模块化资产 (Modular Assets):

    • 指将复杂的物体(如房屋)拆分为独立的、简单的部件(如墙壁、窗户、地板)。开发者通过组合这些部件来搭建场景。
  • Lumen卡片 (Lumen Cards):

    • 为了快速计算GI,Lumen并不会直接处理高精度的模型

    • 相反,它会为每个静态网格体预先计算并生成一组极其简单的平面(卡片) 来代表这个物体,Lumen的GI计算是基于这些卡片进行的。

2. 模块化带来的"三难困境" (Catch-22)

问题1:单一复杂网格体 → GI计算错误

  • 场景: 如果你将一个复杂的物体(比如带完整内部房间的房屋)制作成一个单独的Mesh

  • 后果: Lumen无法为这个复杂形状创建出贴合的、简单的Lumen卡片。

  • 结果: 导致GI计算出错,在无法正确计算的区域出现粉色瑕疵

  • 基本规则: 因此,使用Lumen的基本规则是:复杂形状应由简单的模块化资产拼搭而成

问题2:海量的Lumen卡片 → 性能崩溃

  • 场景: 你遵循了规则1,使用了大量模块化资产(墙、窗等)来搭建建筑。

  • 后果: 如果每一个模块化部件都有自己的Lumen卡片,那么一栋建筑就会生成海量的Lumen卡片

  • 结果: 导致处理负载和显存占用激增,无法实时运行。

问题3:合并卡片的副作用 → 内部GI失效

  • 解决方案 (合并): UE允许将Lumen卡片进行合并。你只需为一组模块化资产(如一整栋建筑的所有部件)的静态网格体组件设置一个相同的 Ray Tracing Group ID

  • City Sample 示例: 在City Sample中,整栋建筑的所有部件共享一个ID,它们被合并为一个单一、简化的Lumen卡片

  • 结果 (优点): 极大地减少了Lumen卡片的数量,显著降低了性能开销。

  • 结果 (缺点): 这又带回了问题1。被合并后的卡片过于简单(例如只是一个方盒),完全丢失了建筑的内部结构

  • 关键事实: 这就是为什么在City Sample中,你无法进入任何一栋建筑的原因。

核心洞察:Lumen的当前权衡

  • 现状: 目前Lumen没有一种机制能同时完美地处理建筑的外部和内部

  • 建议方案:

    1. 将建筑的外部和内部分开创建

    2. 通过游戏逻辑来动态切换可见性。例如,当玩家在室外时,关闭内部模型的可见性和GI计算,反之亦然。

  • 关键建议: 在使用模块化资产构建场景时,积极使用 Ray Tracing Group ID 来分组Lumen卡片,这有助于优化性能。但你必须充分理解这会对内部空间的GI计算带来的副作用


七、 Nanite (虚拟化几何体)

核心问题:Nanite对低多边形场景是否有效?

这是一个常见疑问:对于轻量级、低多边形的场景,使用Nanite是否反而会更慢?

测试1:轻量级场景 (Sol City)

  • 条件: 将一个轻量级场景 (Sol City) 的所有网格体(平均约1,000面)转换为Nanite。测试时Lumen 和 VSM 均开启

  • 结果:

    • Nanite 开启9.9 ms

    • Nanite 关闭7.85 ms

  • 结论: 在这个特定的轻量级场景中,禁用Nanite反而快了约 1.4 ms

  • 原因: Nanite 本身带有一定的 基础开销 (Baseline Overhead)。在这个场景中,Nanite的这点基础开销超过了它优化渲染所带来的收益。

测试2:高多边形场景 (PCG 树林)

  • 条件: 使用PCG放置300棵树,每棵树约146万面。

  • 结果:

    • Nanite 开启10.28 ms

    • Nanite 关闭 > 100 ms

  • 结论: 在高多边形场景下,Nanite 带来了巨大的性能优势

核心洞察:如何评估Nanite

  • Nanite的性能曲线:

    1. Nanite 确实存在基础开销

    2. 但一旦启用,其性能开销随多边形数量的增长极其缓慢

    3. (对比测试1和2:多边形数量增加了数千倍,但总帧时仅从9.9ms增加到10.28ms,几乎持平)。

  • Nanite的隐性价值: 最大的好处之一是它自动处理了所有LOD,极大地节省了美术和开发者的优化时间。

  • 最终建议:

    • 不要轻易下结论说“Nanite对简单场景太重了,我们关掉吧”。

    • 一定要仔细测量 (Measure Carefully)。在做出决定之前,请在你的具体场景中进行评估和测试。