UE5 Graphics Deep Insights From Japan
UE5 Graphics Deep Insights From Japan | Unreal Fest Bali 2025
虚幻引擎在日本市场的应用概览
主要游戏作品
- 多款主机大作使用虚幻引擎开发:《最终幻想7》、《王国之心》、《皇牌空战》、《皮克敏》、《Hi-Fi Rush》
- 虚幻引擎不仅适用于 照片级写实(Photorealistic) 风格,也广泛用于 非照片级写实(Non-Photorealistic / NPR) 风格,例如 《女神异闻录》 系列
游戏之外的应用场景
- 动画制作:日本热门动画(如"Pikua")使用虚幻引擎制作包含全角色动画的片尾影像,相关工作流已发布博客(基于 UE4)
- 漫画创作:利用虚幻引擎决定漫画分镜布局,渲染背景图像后再进行手工修饰
- VTuber 与虚拟演出:VTuber 在日本已成为主流文化,线下演唱会可吸引数万名观众,这些演出充分利用了虚幻引擎灵活强大的实时渲染能力
日本市场的独特特征
- 风格化图形(Stylized Graphics) 深受偏爱,受漫画和动画文化影响深远
- 主要 3D 游戏平台为 主机(Console),尤其是 Switch 和 PlayStation,而非 PC 或移动端
- 因此对 严格的性能优化 有极高要求
GPU 性能分析(GPU Profiling)
核心问题:ProfileGPU 的测量结果到底有多准确?
这是本节的核心议题。ProfileGPU 是日常开发中最常用的 GPU 性能分析命令之一,无论在编辑器中还是在运行时/主机上都广泛使用。但其测量精度与 异步计算(Async Compute) 的支持状况密切相关。
UE5 中异步计算的演进
UE5 越来越多地使用 异步计算(Async Compute) 来提升 GPU 性能和效率。核心思路是让渲染相关的处理在 图形管线(Graphics Pipe) 和 计算管线(Compute Pipe) 之间 异步并行 执行,从而更充分地利用 GPU 资源。
UE 5.5 及更早版本的局限
- Unreal Insights 无法显示异步计算管线的活动
- 例如 Lumen Screen Probe(Lumen 的关键处理步骤)在 Insights 中完全不可见
- 只有 手动关闭 Lumen 的 Async Compute 后,这些 Pass 才会出现在 Insights 中
ProfileGPU在测量时会禁用异步计算- 这意味着测量结果 没有包含异步计算带来的性能收益
- 因此 测量结果不准确,无法反映真实的 GPU 工作负载
UE 5.6 的改进
- Unreal Insights 现已支持可视化 Compute Pipe,无需额外设置即可看到异步计算活动
ProfileGPU也开始支持 Async Compute,能同时显示 Compute Pipe 和 Graphics Pipe- 注意:编辑器中的
ProfileGPU专用 UI 窗口在 5.6 中被移除,结果仅输出到 Output Log
UE 5.7 的进一步变化
ProfileGPU的 UI 窗口 重新恢复- 重要区别:5.7 版本的
ProfileGPU不会禁用异步计算,因此提供的是 更准确的性能开销百分比测量 - 局限性:虽然测量更准确,但它 不显示 Compute Pipe 的具体活动内容
- 如果需要看到完整的异步计算全貌,应使用 Unreal Insights
异步计算给性能分析带来的挑战
由于异步计算的引入,许多处理过程现在互相重叠(Overlap),这使得 孤立地观察单个 Pass 的 GPU 工作负载变得更加困难。
具体示例:
- 在 Insights 的时间线图中,Lumen Scene Lighting 看起来可能只花费约 2 毫秒
- 但实际上,其内部包含许多 GPU 处于等待状态(Waiting/Idle) 的片段
- 表面上的时间跨度并不等于真正的计算负载
实用建议:
- 如果需要 精细调优和优化某个具体的渲染 Pass,可以 临时禁用该 Pass 的异步计算,使其以同步方式运行,从而获得更清晰的单独性能数据
- 讲者还展示了 Lumen 中多个异步处理相关的控制台变量(CVar),可按需逐个禁用
是否还需要平台级 GPU Profiler?
答案是:绝对需要。
Unreal 内置工具的定位
| 工具 | 优势 | 局限 |
|---|---|---|
| ProfileGPU | 快速定位性能瓶颈所在 | 无法解释"为什么"某个 Pass 开销大 |
| Unreal Insights | 轻量级、可视化异步计算全貌、适合日常分析 | 同样无法深入到硬件级别的原因分析 |
平台/硬件厂商提供的 Profiler
- 包括 PIX(Xbox/Windows)、Razor(PlayStation)、以及各 GPU 厂商的专用工具
- 通过 帧捕获(Frame Capture),可以快速判断某个 Pass 的开销来源:
- 计算量过大(Heavy Computation)
- 纹理访问过多(Excessive Texture Access)
- 寄存器使用量过高(High Register Usage / Register Pressure)
- 与异步计算的重叠方式不当
- 使用平台级 Profiler 可以 避免在无效或方向错误的优化上浪费时间
本节核心总结
- 由于 异步计算的广泛采用,理解单个 Pass 的真实 GPU 负载变得更加困难
- 从 UE 5.6 开始,Unreal 的各种内置工具已支持 异步计算的可视化
- 若需精确观察单个 Pass 的处理负载,应 临时禁用对应的异步计算
- Unreal Insights 是轻量级首选的日常分析工具
- 要深入理解 "为什么某个 Pass 开销大",必须使用 硬件厂商提供的 GPU Profiler
Shader Complexity 视图模式的误区与正确用法
基本原理
- Shader Complexity 视图模式 用于可视化每个像素执行的 着色器指令总数
- 一位日本用户曾在社交媒体上开玩笑称要成立 "Shader Complexity 视图消灭委员会",这背后有深层原因
可视化机制
- 不透明(Opaque)区域:在默认渲染器中,每个像素 只计算一次
- 半透明(Translucent)渲染 是 叠加式(Additive) 的:半透明层越多重叠,每像素的开销就越高
- Shader Complexity 视图的 适用场景:
- 快速识别 不透明着色器指令数过高 的区域
- 发现 多层半透明绘制重叠 的区域
- 或两者兼有的情况
查看实际着色器指令数
- 在 材质编辑器(Material Editor) 中有一个 Platform Stats 窗口
- 可以根据具体的材质设置,查看 各平台对应的着色器指令数
核心洞察:指令数 ≠ 性能开销
这是本节最重要的结论。
生动类比
- 就像小孩说"爸爸做个煎饼"和"在大会上做两场演讲"——两句话写出来都只是一行文字,但 实际工作量完全不同
- 着色器指令也是一样:有些指令涉及 纯计算,有些涉及 纹理采样(Texture Access),两者的 实际性能开销差异巨大
GPU 编译器的智能优化
- 现代 GPU 着色器编译器非常聪明
- 以 Alpha Test(透明度测试) 为例:当着色器包含
discard指令时,编译器可能会 优先计算 Alpha 条件,只有当像素不被丢弃时才继续执行后续计算 - 这意味着实际执行的工作量可能远小于指令总数所暗示的
极端反例演示
| 示例 | 指令数 | 实际 GPU 开销 | 说明 |
|---|---|---|---|
| 恶意材质设置(球体) | 39 条指令 | 20 毫秒 | 低指令数,极高开销 |
| 刻意增加指令 | 2533 条指令 | 0.04 毫秒 | 高指令数,几乎无开销 |
这充分证明:指令数与性能开销之间没有直接的线性关系。
Shader Complexity 视图的另一大缺陷:Masked Material 的误导
- 使用 遮罩材质(Masked Material) 制作的树叶形状,透明区域实际上 仍然在运行着色器并执行 Alpha 测试
- 但这部分开销 完全没有反映 在 Shader Complexity 视图中
- 结果是:遮罩材质被可视化为 完全不透明材质 的样子,造成 严重误导
- 这很可能就是那位日本用户发推吐槽的原因
推荐用法与优化建议
- Shader Complexity 视图的最佳用途:仅用于检查 半透明元素的重叠情况
- 正确的材质优化方法:使用 详细的 GPU Profiler(如 Unreal Insights 或
ProfileGPU)来精确定位 真实的性能瓶颈 - 最危险的做法:仅因为 Shader Complexity 视图显示为红色或白色,就花大量时间 削减指令数——这可能是 无效优化,既浪费时间又可能牺牲画面质量
TSR(Temporal Super Resolution,时域超分辨率)
4K 原生渲染的性能压力
- 以 City Sample 场景为例,4K 原生渲染在某 GPU 上耗时约 57 毫秒(低于 20 FPS)
- 随着场景物体增多、渲染技术日趋复杂,4K 分辨率渲染依然 非常昂贵
TSR 的基本工作原理
- TSR 是 UE 内置的 时域上采样方法
- 在渲染管线中,TSR 位于 景深(Depth of Field)之后,将较低的内部分辨率 上采样到目标分辨率
- 效果对比:1080p 经 TSR 上采样后与 4K 原生渲染之间 几乎看不出差异
- 性能收益:从 57 毫秒降至约 16 毫秒(示例数据),因为 Nanite 和 Lumen 都依赖内部分辨率,所以 TSR 也大幅降低了它们的负载
TSR 的关键机制:多帧采样
TSR 通过 参考过去多帧的数据 来实现上采样,这带来了几个需要注意的问题:
内部分辨率与帧率的影响
- 输出分辨率 = 目标分辨率 时:无需额外操作,直接使用即可
- 内部分辨率降低 时:TSR 需要 参考过去的帧 来补充信息以达到高分辨率
- 内部分辨率进一步降低 时:需要参考 更久远的帧
- 帧率影响:在 30 FPS 下需要的采样帧数与 60 FPS 相同,但这意味着 TSR 需要参考 时间上两倍久远的帧
鬼影问题(Ghosting)
- 根本原因:当分辨率过低或帧率过慢时,TSR 需要参考 非常古老的帧,导致全屏出现 鬼影/拖影
- 极端示例:仅以 25% 内部分辨率 渲染时:
- 摄像机移动 时:整个画面 非常模糊
- 摄像机静止 时:TSR 能逐渐生成 越来越高分辨率 的清晰画面——这是 TSR 在静态场景下的强大优势
重要警告:CPU 导致的掉帧也会影响 TSR
- 即使 GPU / 渲染开销很低,CPU 端的动画、加载等操作导致 FPS 下降,同样会在 TSR 中产生鬼影
- 这种 CPU 端的开销 无法通过动态分辨率或任何 GPU 技术来缓解
- 要维持 TSR 质量,必须保持 CPU 和 GPU 性能都稳定
TSR 与速度向量(Velocity Vector)
- TSR 使用 速度向量(Velocity) 来估算帧间的变化
- 如果速度向量 未正确写入,TSR 将无法正确工作
- 错误示例:物体在旋转,但速度向量未变化 → 物体上出现 严重模糊/鬼影
- 修正后:生成正确的速度向量后,鬼影 完全消失
TSR 文档资源
- 从 UE 5.4 开始,TSR 的官方文档已经 大幅扩充,详尽到可以出版成一本书
- TSR 是 平衡画质与性能的关键功能,强烈建议仔细阅读官方文档
TSR 要点总结
| 因素 | 影响 |
|---|---|
| 低内部分辨率 / 低帧率 | 需要更多时间积累样本来生成高分辨率图像,导致严重鬼影 |
| 速度向量不正确 | 在对应区域产生鬼影和模糊 |
| CPU 掉帧 | 同样会触发鬼影,且无法用 GPU 技术解决 |
| 静态场景 | TSR 表现极佳,即使极低分辨率也能逐帧收敛到高画质 |
Megalights(巨量光源)
功能定位
- Megalights 是一项 正在开发中的激动人心的新特性
- 设计目标:即使在 主机平台 上也能高效支持 大量光源
核心原理:固定采样预算
- Megalights 之所以能支持大量光源,是因为 每像素每帧的最大采样数是固定的
- 这意味着即使光源数量增加,处理开销也不会显著增长
与传统方法的对比
| 方面 | 传统光照渲染 | Megalights |
|---|---|---|
| 计算方式 | 为每个光源逐一进行光照计算,确保精确且物理正确 | 固定采样预算,智能分配给最重要的光源 |
| 性能随光源数量的变化 | 线性增长——每增加一个光源,开销就增加 | 基本不变——光源数量增加,开销保持稳定 |
| 设计理念 | 优先 渲染精度,牺牲性能 | 优先 性能稳定,可能引入微小误差 |
| 潜在问题 | 光源过多时性能急剧下降 | 可能出现 微小的误差或可见瑕疵(Artifacts) |
重要警告:仍为实验性功能
- Megalights 当前仍处于 实验性(Experimental) 阶段
- 尽管它令人兴奋且功能强大,许多开发者跃跃欲试
- 但 强烈建议不要在正式生产项目中使用 Megalights
- 目前没有关于何时移除实验性标签的具体时间表
Virtual Texture(虚拟纹理)与 VSSM(虚拟阴影贴图)
Virtual Texture 的注意事项
- 从 UE 5.6 开始,Virtual Texture 默认开启
- 关键限制:虚拟纹理的最小尺寸等于其 Tile Size,默认为 128×128
- 系统 不会生成小于该尺寸的 Mip Map
- 结果:高频率虚拟纹理在远处可能产生 严重的摩尔纹(Moiré Pattern),画面出现明显瑕疵
- 缓解方案:TSR 的 Shading Rejection 选项可以极大改善摩尔纹问题
- 当 Scalability 设为 High 或以上(Epic、Cinematic)时,该选项 默认开启
- 但这 并非完美解决方案,某些相机角度仍可能出现摩尔纹
- 目前 没有已知的完美解决方案
VSSM(Virtual Shadow Maps,虚拟阴影贴图)的优化
为何关注 VSSM?
- 一些开发者 放弃使用 VSSM,原因是:
- 默认的 Page Pool Size 为 512MB
- 内存消耗 和 GPU 负载 对其项目来说过高
- 但实际上,VSSM 的内存和 GPU 负载已有 大幅优化空间
UE 5.4 的重大更新
- 引入了 动态自动调整 Page LOD 的功能,根据 Pool Size 自动适配
- 实际效果示例:
- Page Pool Size 从 496MB → 100MB
- 内存消耗从 512MB → 仅 60MB
- 阴影仍然渲染良好,因为 Page LOD 自动提升
- 这是一个 非常强大的系统,但很多人还不知道
- 关键控制台变量:
r.Shadow.Virtual.MaxPagePoolLoadFactor(建议尝试调整)
UE 5.6 的新特性
- 新增了基于性能 动态降低 VSM 处理负载 的功能,类似于 动态分辨率(Dynamic Resolution) 的思路
- 可根据实际帧率自动调节 VSM 的工作量
VSSM 总结建议
- 如果觉得 VSM 内存占用过高,先尝试 减小 Page Pool Size 并配合相关控制台变量
- UE 5.4 及以上版本 的自动 LOD 调整非常值得启用
Lumen 的实际使用陷阱
Lumen 的优势
- 实现 无需烘焙的全局光照(GI),支持运行时 动态光照
- 大幅减少 光照烘焙工作流 的时间成本
Lumen 的已知缺陷
- 与 TSR 类似,Lumen 依赖时间上累积的信息,可能产生 鬼影(Ghosting) 或 拖尾伪影(Trailing Artifacts)
- 性能开销较高(虽然持续改进中)
核心问题:模块化资产 vs Lumen Card 的矛盾
这是 Epic Games Japan 在支持日本开发者过程中遇到的 最大问题,尤其是当从外部导入资产(如 Mega Scans 或 FAB)时。
什么是 Lumen Card?
- Lumen 为了快速计算 GI,会用 极简的平面(Lumen Cards) 包裹每个物体
- Lumen Card 是 预计算的,对应每个 Static Mesh
- 即使是复杂形状(如树木),Lumen Card 也只是 简单的盒子形状
问题一:复杂单体网格无法正确生成 Lumen Card
- 如果将整个房屋内部做成 一个完整的复杂 Mesh,Lumen Card 无法适配其形状
- 结果:出现 粉色区域,表示 Lumen 无法正确计算着色
- 基本规则:使用 Lumen 时,复杂形状应由 多个简单模块化资产(Modular Assets)组合而成
问题二:模块化资产导致 Lumen Card 数量爆炸
- 如果每个模块化组件都有独立的 Lumen Card,一栋建筑可能产生 数量极多的 Lumen Card
- 处理负载和内存消耗 会急剧飙升,无法实时处理
解决方案:Ray Tracing Group ID 合并 Lumen Card
- UE 提供了 合并相同 ID 对象的 Lumen Card 的机制
- 对应属性:Static Mesh Component 的
Ray Tracing Group ID - 相同 ID 的物体,其 Lumen Card 会被合并
- 无论 Lumen 使用 软件光追还是硬件光追,此机制均有效
- City Sample 的做法:每栋建筑的所有模块化组件设置 相同的 Ray Tracing Group ID,整栋建筑只有 一个 Lumen Card
- 效果:大幅减少 Lumen Card 数量,降低处理负载
副作用:室内外无法兼得
- 合并 Lumen Card 后,简单的盒状 Card 无法正确覆盖建筑内部
- City Sample 中没有任何建筑可以进入内部,正是这个原因
- 目前 没有已知的 Lumen 机制可以同时正确处理建筑的外部和内部
- 实际应对方案:
- 将建筑的 外部和内部分开创建
- 在游戏逻辑层面 切换内外部的可见性(Visibility)
- 减少不必要的 Lumen 内部计算
Lumen 总结建议
- 每个新版本都在持续进行 重大优化和功能改进
- 如果使用模块化资产构建场景,务必使用 Ray Tracing Group ID 对 Lumen Card 进行分组
- 可以提升 Lumen 场景质量并降低性能开销
- 但必须 充分理解其副作用(尤其是室内外问题)
Nanite 的性能评估
核心问题:Nanite 对低多边形/轻量场景是否有效?
测试一:轻量场景(Sol City 示例项目)
- 将 Sol City 中所有 Mesh 转换为 Nanite
- 大多数 Mesh 仅约 1,000 多边形
- 测试条件:启用 Lumen 和 VSSM
| 配置 | GPU 时间 |
|---|---|
| Nanite 开启 | 9.9 ms |
| Nanite 关闭 | 7.85 ms |
- Nanite 关闭时反而 快约 1.4 ms
- 原因:对于轻量场景,Nanite 的 基础开销(Baseline Overhead)超过了其带来的收益
测试二:高多边形场景(大量树木)
- 单棵树 Mesh 约 146 万多边形
- 使用 PCG 放置约 300 棵树
| 配置 | GPU 时间 |
|---|---|
| Nanite 开启 | 10.28 ms |
| Nanite 关闭 | 超过 100 ms |
- Nanite 的 性能优势巨大,接近 10 倍加速
关键发现:Nanite 的性能扩展特性
- 对比两个测试:从轻量场景到高多边形树木场景,启用 Nanite 时 GPU 时间仅增加了约 1 ms(从 9.9 → 10.28 ms)
- 这说明 Nanite 的性能影响随多边形数量的增加呈非常平缓的增长
- 当然,不使用 Nanite 时,可以通过手动创建精细的 LOD 模型 来优化性能,但 Nanite 自动处理这一切 是其巨大优势
Nanite 总结建议
- Nanite 存在 固定的性能基础开销
- 在非常轻量的场景中,关闭 Nanite 可能更快
- 不要草率下结论 说"Nanite 对简单场景太重,直接关掉"
- 正确做法:仔细测量(Measure) 和 评估你的具体场景,用数据做决策
全文要点回顾
| 主题 | 核心要点 |
|---|---|
| GPU Profiling | UE 5.6/5.7 改进了 Async Compute 的可视化与测量支持 |
| Shader Complexity | 指令数 ≠ 性能开销,仅适合检查半透明重叠 |
| TSR | 多帧累积上采样,注意 Ghosting 与速度缓冲区问题 |
| Virtual Texture | 5.6 默认开启,注意最小 Mip Map 导致的摩尔纹 |
| VSSM | 减小 Page Pool Size + 自动 LOD 可大幅降低内存 |
| Lumen | 模块化资产需用 Ray Tracing Group ID 分组,注意室内外限制 |
| Nanite | 有固定开销,轻量场景可能不划算,但高多边形场景收益巨大,务必实测 |