着色器编译和 PSO
着色器排列组合的数量会影响编译时间、打包大小和运行时卡顿。Vite 的主要控制手段是 VITE_RT_PSO_DEBLOAT,它会移除未包含的特效的光线追踪排列组合。而您主要的控制手段是着色器模型规范和 PSO 缓存。
着色器排列组合是指针对特定特性组合编译的着色器变体之一。虚幻引擎以组合方式生成排列组合,因此每个独立选项都会使排列组合的数量大致翻倍。
这会影响四个方面:完整构建所需的时间、打包后的游戏大小、玩家机器上首次运行着色器编译所需的时间,以及游戏在首次遇到材质时是否会出现卡顿。
光线追踪排列
光线追踪是最棘手的情况,因为光线追踪管线状态对象必须包含所有可能被调度的光线生成着色器。即使控制台变量设置为 0,也不会移除其着色器——它们仍然会被编译、打包并绑定到管线中。
VITE_RT_PSO_DEBLOAT(默认值为 1)通过对 Vite 推荐配置之外的光线追踪效果(例如逐像素光线追踪全局光照、RTXDI、路径追踪、光线追踪半透明、网格和水体焦散、光线追踪反射捕获以及非延迟反射路径)从 ShouldCompilePermutation 返回 false 来解决这个问题。
这是一个很大的改进。这也是这些效果在默认版本中无法正常工作的原因。完整详情请参阅编译时开关部分。
材质排列组合
您可以控制材质着色器数量的以下选项:
着色模型。 每个使用的着色模型都会增加排列组合。使用默认光照和 Callisto BRDF 的项目编译的着色器数量远少于使用六个模型的项目。这是实际的预算,而非理论预算。
材质使用标志。 材质上的每个Used With(使用于)标志都会增加一个顶点工厂排列组合:用于骨骼网格、实例化静态网格、粒子精灵、样条线等等。Unreal 会在遇到新的使用情况时自动设置这些标志,这意味着材质可能会悄悄地积累不再需要的标志。请检查这些标志。
静态开关。 每个静态开关参数都会使排列组合数量翻倍。两个开关对应四个变体;十个开关对应 1024 个变体。当排列组合数量过多时,请使用动态分支或单独的材质。
质量级别和功能级别。 项目目标着色器平台和质量级别的每个值都会乘以上述所有值。
细分曲面。 启用材质细分会增加外壳和域着色器排列组合。
编译时间
参考数据来自 Vite 代码库,在 Ryzen 9 9950X3D 上测得:
| 配置 | 完整引擎构建 |
|---|---|
| 完整代码库 | 约 15 分钟 |
| 不包含 Vite 插件 | 约 12 分钟 |
Houdini 是新增插件中占用资源最多的。请参阅精简指南,了解如何移除不需要的插件。
为了加快着色器编译速度:
- 如果 CPU 核心数和内存足够,请在
BuildConfiguration.xml文件中增加 worker 数量。每个 worker 都需要内存,因此过度分配内存会导致交换,反而会降低性能。 - 团队内部共享派生数据缓存。对于多人团队来说,这是最有效的优化方法:任何人编译一次的着色器都可以供所有人使用。
- 避免修改全局着色器头文件。对广泛使用的
.ush文件进行更改会导致所有内容重新编译。
PSO 缓存
管线状态对象 (Pipeline State Object, PSO) 将着色器和渲染状态打包成 GPU 驱动程序实际需要的对象。在材质首次绘制时创建 PSO 会导致游戏发布时出现着色器编译卡顿。
PSO 缓存通过记录构建实际使用的 PSO,并在启动或加载期间预编译它们来解决这个问题。
设置 PSO 缓存
-
在“项目设置”>“打包”中启用 PSO 缓存。
-
打包一个启用日志记录的版本,并完整运行一遍,确保覆盖到最终发布游戏中包含的每个关卡、每个材质和每个特效。覆盖范围至关重要:录制过程中未遇到的 PSO 仍然会导致卡顿。
-
从构建版本中收集已录制的 PSO 缓存文件。
-
使用着色器管线缓存工具将它们合并成一个单独的缓存文件。
-
将缓存文件包含在最终发布版本中,并验证卡顿问题是否已解决。
这项工作确实非常繁琐,而且通常会被拖延到最后。务必在内容锁定之前安排好这项工作,而不是之后。
缓存问题
过时的着色器缓存会导致虚幻引擎中一些最令人困惑的故障:着色器与源文件不匹配、材质渲染错误、编辑器加载时崩溃,以及编译时开关的更改似乎没有任何效果。
如果您更改了 VITE_RT_PSO_DEBLOAT 或任何其他影响着色器排列的开关,请清除缓存。请参阅缓存管理中的 WipeShaderCache.bat,该脚本会清除引擎级派生数据缓存、中间着色器和着色器调试信息。
诊断
| 症状 | 可能原因 |
|---|---|
| 首次出现特效或材质时出现卡顿 | 缺少 PSO 缓存条目 |
| 构建后首次启动时间过长 | 全局着色器重新编译,通常是由于头文件更改导致 |
| 每次启动时着色器都重新编译 | DDC 未持久化,或着色器哈希的输入不确定 |
| 控制台变量无可见效果 | 功能被编译掉。请参阅编译时开关。 |
| 编译时间随时间推移而增加 | 由于累积的材质使用标志和静态开关导致排列组合变化 |
当您需要了解实际编译的内容时,r.ShaderDevelopmentMode 1 和 r.DumpShaderDebugInfo 1 会生成诊断输出。