您想找什么?
Hero background image
管理 PC 和控制台游戏的 GPU 使用情况

这是为您的 Unity 项目介绍优化技巧的系列文章的第三篇。将它们作为指南,以更少的资源运行更高的帧速率。尝试过这些最佳实践后,请务必查看本系列的其他页面:

了解目标硬件的限制,以及如何配置 GPU 以优化图形渲染。试试这些技巧和最佳实践,以减少 GPU 的工作量。

在免费电子书中还能找到更多最佳实践、 优化游戏机和 PC 的游戏性能.

Unity 引擎中的 SRP Batcher
SRP BATCHER 可帮助您批量绘制调用。
使用绘制调用批处理

要在屏幕上绘制游戏对象,Unity 会向图形 API(如OpenGLVulkanDirect3D)发出绘制调用。每次绘制调用都需要耗费大量资源。

绘制调用之间的状态变化(如切换材料)会对 CPU 端造成性能开销。PC 和控制台硬件可以进行多次绘制调用,但每次调用的开销仍然很高,因此需要尽量减少调用次数。在移动设备上,拔号呼叫优化至关重要。您可以通过批处理绘制调用来实现这一点。

批处理绘制调用可最大限度地减少这些状态变化,并降低渲染对象的 CPU 成本。Unity 可以通过高清渲染管道(HDRP) 或通用渲染管道(URP) 使用多种技术将多个对象合并成较少的批次:

  • SRP 配料:在 "高级"下的 "管道资产"中启用SRP Batcher。使用兼容着色器时,SRP Batcher可减少绘制调用之间的 GPU 设置,并使材质数据持久存在 GPU 内存中。这还能大大加快 CPU 的渲染速度。使用更少的着色器变体和最少的关键字来改进 SRP 批处理。请查阅SRP 文档,了解您的项目如何利用这一渲染工作流程。
  • GPU实例化来优化渲染。如果有大量具有相同网格和材质的相同对象,可使用GPU 实例化功能通过图形硬件批量处理这些对象。要启用 GPU 实例化,请在 "检查器"的 "项目"窗口中选择材质,然后选中 "启用实例化"。
  • 静态配料:对于非移动几何体,Unity 可以减少对共享相同材质的网格的绘制调用。这比动态批处理更有效,但会占用更多内存。在 "检查器 "中将所有从不移动的网格标记为"批处理 静态"。Unity 会在构建时将所有静态网格合并为一个大网格。StaticBatchingUtility类还允许您在运行时创建这些静态批次(例如,在生成非移动部件的程序级后创建)。
  • 动态批处理对于小型网格,Unity 可以在 CPU 上对顶点进行分组和变换,然后一次性绘制完成。但请注意,除非您有足够的低多边形网格(每个网格的顶点不超过 300 个,顶点属性总数不超过 900 个),否则不应使用此方法。否则,启用它将浪费 CPU 时间来查找要批处理的小网格。

您可以通过几种简单的方法将批处理功能最大化:

  • 在场景中尽量少用纹理。较少的纹理需要较少的独特材料,因此更容易批量生产。此外,尽可能使用纹理图集
  • 始终以尽可能大的图集尺寸烘焙光贴图。较少的光贴图需要较少的材质状态变化,但要注意内存占用。
  • 小心不要无意中将材料实例化。访问 渲染器.材质脚本会复制素材,并返回对新副本的引用。这将破坏任何已包含该材料的现有批次。如果您想访问批处理对象的材质,请使用Renderer.sharedMaterial来代替。
  • 在优化过程中,使用Profiler或渲染统计,留意静态和动态批处理次数与总绘制调用次数的对比。

更多信息请参阅绘图调用批处理文档。

框架调试器界面
帧调试器会分解每个渲染帧。
检查框架调试器

使用 "帧调试器 "将播放定格在单帧上,并逐步了解 Unity 如何构建场景。这样,您就能发现优化机会。查找不必要渲染的游戏对象,并禁用它们以减少每帧的绘制调用。

帧调试器的一个主要优势是可以将绘制调用与场景中的特定 GameObject 关联起来。这使得调查某些问题变得更容易,而外部框架调试器可能无法做到这一点。

注意:框架调试器不会显示单个绘制调用或状态变化。虽然只有原生GPU 分析器才能提供详细的绘制调用和时序信息,但帧调试器对于调试流水线问题或批处理问题仍然很有帮助。

详情请阅读框架调试器文档

优化填充率,减少透支

填充率是指 GPU 每秒能呈现到屏幕上的像素数量。如果您的游戏受到填充率的限制,这意味着它试图在每帧绘制的像素数超过了 GPU 的处理能力。

在同一像素上多次绘制称为过度绘制。过度绘制会降低填充率,并耗费额外的内存带宽。最常见的透支原因是

  • 重叠的不透明或透明几何体
  • 复杂着色器,通常需要多次渲染传递
  • 未优化的粒子
  • 重叠的用户界面元素

虽然应尽量减少超支的影响,但解决超支问题没有放之四海而皆准的方法。尝试使用以下技术来减少其影响。

减少批次数量

与其他平台一样,在游戏机上进行优化通常意味着减少抽签调用批次。以下是一些可能会有所帮助的技巧:

  • 使用 遮挡剔除移除隐藏在前景物体后的物体,减少过度绘制。请注意,这需要额外的 CPU 处理,因此请使用 Profiler 来验证将工作从 GPU 转移到 CPU 是否真的有益。
  • 如果有许多对象共享相同的网格和材质,GPU 实例化还可以减少批次。限制场景中的模型数量可以提高性能。如果做得巧妙,就可以构建一个复杂的场景,而不会让它看起来重复。
  • SRP Batcher可以通过批处理绑定绘制GPU 命令来减少绘制调用之间的 GPU 设置。要从 SRP 批处理中获益,可根据需要使用尽可能多的材料,但仅限于少数兼容着色器(例如 URP 和 HDRP 中的 "点亮"和"未点亮"着色器)。
闭塞剔除界面
遮挡剔除的一个例子。
注意删减

每台摄像机都会进行剔除,这可能会对性能产生很大影响,尤其是同时启用多台摄像机时。Unity 使用两种剔除方式:

  • 每台摄像机都会自动进行剔除。它可以确保在 视图的游戏对象不会被渲染,以节省性能。
  • 您可以通过Camera.layerCullDistances 手动设置每个图层的剔除距离。这样就可以在比默认的farClipPlane属性。为此,请将游戏对象组织到图层中。使用.layerCullDistances数组为 32 个图层中的每个图层分配一个小于 farClipPlane 的值(或使用 0 默认为 farClipPlane)。
  • 团结 "先逐层剔除。它只会在摄像机使用的图层上保留游戏对象。之后,Frustum 剔除功能会移除摄像机 Frustum 以外的任何游戏对象。
  • Frustum 剔除工作是作为一系列利用可用工作线程的工作来执行的。每个图层剔除测试都很快(基本上只是一个位屏蔽操作)。不过,如果游戏对象数量较多,这一成本还是会增加。如果这成为您项目中的一个问题,您可能需要实施一些系统来将您的世界划分为 "扇区",并禁用位于 "相机边界 "之外的扇区,以减轻 Unity 的 "图层/边界 "剔除系统的压力。
  • 如果 "摄像机 "无法看到任何游戏对象,则 "遮挡剔除"功能会从 "游戏 "视图中移除这些游戏对象。隐藏在其他对象后面的对象仍有可能渲染并耗费资源。使用遮挡剔除功能丢弃它们。
  • 例如,如果房门紧闭,摄像机无法看到房间内的情况,就没有必要渲染房间。如果启用遮挡剔除功能,可以显著提高性能,但同时也会占用更多的磁盘空间、CPU 时间和内存。Unity 在构建过程中会烘焙闭塞数据,然后需要在加载场景时将其从磁盘加载到 RAM 中。
  • 在 "相机 "视图之外的 "Frustum "剔除是自动进行的,而 "Occlusion "剔除则是一个烘焙过程。只需将对象标记为 "静态"、"遮挡"或"被遮挡",然后通过 "窗口">"渲染">"遮挡消除"对话框进行烘焙。

如需了解更多信息,请参阅 "使用遮挡剔除 "教程

利用动态分辨率

通过 "允许动态分辨率相机 "设置,可以动态缩放单个渲染目标,以减少 GPU 的工作量。在应用程序帧频降低的情况下,可以逐步降低分辨率,以保持帧频一致。

如果性能数据显示,由于 GPU 的限制,帧频即将下降,Unity 就会触发这种缩放。您也可以使用脚本手动预先触发这种缩放。如果您正在处理应用程序的 GPU 密集型部分,这将非常有用。如果逐步缩放,动态分辨率几乎不会被察觉。

有关支持的平台列表,请参阅动态分辨率手册页面

摄像机堆叠演示
在 URP 中堆叠摄像机:用不同的相机设置渲染枪和背景。
检查多个摄像头视图

有时,您需要在游戏中从多个角度进行渲染。例如,在第一人称射击游戏(FPS)中,通常会以不同的视场(FOV)分别绘制玩家的武器和环境。这样可以防止前景物体通过背景的广角 FOV 看起来失真。

您可以使用 相机堆叠来呈现多个摄像机视图。不过,每台摄像机仍需进行大量的剔除和渲染工作。无论是否在进行有意义的工作,每台摄像机都会产生一些开销。

只使用渲染所需的相机组件。在移动平台上,即使不进行任何渲染,每个活动摄像头也会占用多达 1 毫秒的 CPU 时间。

使用详细程度

当物体向远处移动时,细节级别(LOD) 可以调整或切换它们,使其使用分辨率较低的网格和较简单的材质和着色器。这可以增强 GPU 性能。

有关详细信息,请参阅 Unity Learn 上的 "使用 LOD "课程

后处理界面
尽可能简化后期处理效果。
轮廓后期处理效果

后期处理特效进行剖析,查看其在 GPU 上的成本。有些全屏特效(如"绽放"和 "景深")可能很昂贵,因此值得尝试,直到在视觉质量和性能之间找到理想的平衡点。

后期处理在运行时波动不大。一旦确定了 "音量覆盖",就应将后期处理效果分配给总画面预算中的静态部分。

避免使用细分着色器

细分形状将形状细分为更小的版本,可通过增加几何形状来增强细节。虽然在某些例子中,细分效果是最合理的,例如 Unity 演示《亡灵之书》中的树皮,但在游戏机上尽量避免使用细分效果,因为它们对 GPU 的要求很高。

点击此处了解更多有关《死者之书》演示的信息。

用计算着色器取代几何着色器

与 "细分着色器 "一样,几何和顶点着色器每帧可在 GPU 上运行两次,一次是在深度预处理期间,另一次是在阴影处理期间。

如果要在 GPU 上生成或修改顶点数据,计算着色器通常是更好的选择,尤其是与几何着色器相比。在计算着色器中完成工作意味着实际渲染几何图形的顶点着色器可以更快地运行。

了解有关着色器核心概念的更多信息。

好波面和坏波面占用图
好波面占用率与坏波面占用率
以良好的波前占位为目标

当您向 GPU 发送绘制调用时,该工作会分成许多波面,Unity 会将这些波面分配到 GPU 中可用的 SIMD 中。每个 SIMD 可同时运行的波阵面数量都有上限。

波面占用率是指相对于最大值而言,当前正在使用的波面数量。它衡量你对 GPU 潜能的利用程度。用于控制台开发的剖析工具可以非常详细地显示波前占用率。

在上述 Unity 的《死亡之书》示例中,顶点着色器波阵面显示为绿色,像素着色器波阵面显示为蓝色。在下图中,出现了许多顶点着色器波阵面,但像素着色器活动并不多。这表明 GPU 的利用率不足。

如果您正在进行大量顶点着色器工作,却没有产生像素,这可能表明效率不高。虽然波前占用率低并不一定是坏事,但这是一个可以用来开始优化着色器和检查其他瓶颈的指标。例如,如果内存或计算操作导致停滞,增加占用率可以提高性能。另一方面,过多的飞行中波面会导致缓存崩溃,降低性能。

采用异步计算

如果在某些时间段内 GPU 利用率不足,可以利用异步计算将计算着色器工作并行转移到图形队列中。例如,在生成阴影贴图时,GPU 只进行深度渲染。此时像素着色器的工作很少,许多波面仍未被占用。

如果能将一些计算着色器工作与纯深度渲染同步进行,就能更好地利用 GPU 的整体性能。未使用的波面可以帮助进行屏幕空间环境遮蔽(SSAO) 或任何与当前工作相辅相成的任务。

观看 Unite 提供的有关优化高端游戏机性能的课程。

统一关键艺术 21 11
获取免费电子书

我们有史以来最全面的指南之一,收集了 80 多条实用技巧,教你如何优化 PC 和游戏机上的游戏。这些深入的技巧由我们的专家 Success 和 Accelerate Solutions 工程师编写,将帮助您充分利用 Unity 并提高游戏性能。

您喜欢本文吗?
是的!
还行。