查看原文
其他

优化移动端游戏性能 | 来自Unity顶级工程师的图形与资源相关建议

Unity Unity官方平台 2022-05-24

上一篇,我们分享了 Unity Accelerate Solution 团队对性能分析、内存优化和代码架构的优化建议(点击回看)。本次,这支 Unity 最为资深的软件工程师团队将着重介绍怎样提高资源、项目配置和图形的性能。


本系列共有三篇,另外两篇分别介绍了性能分析、内存和代码架构的优化,及物理模拟、UI 和音频的优化,完整教程已搬运至 Unity 中文课堂,欢迎点击“阅读原文”查看:

https://learn.u3d.cn/tutorial/mobile-game-optimization


项目配置


有几个特定的项目设置会影响移动端游戏的性能。


降低或禁用 Accelerometer Frequency(加速度计频率)


Unity 每秒钟会以一定次数统计移动设备的加速度计状态。如果应用并不会用到加速度计,我们完全可以禁用该功能或降低统计频率来获得更好的性能。


请在游戏不使用加速度计时禁用 Accelerometer Frequency


  禁用不必要的 Player 或 Quality 设置


Player 设置中,对不支持的平台禁用 Auto Graphics API,以便防止生成过多着色器变体。如果应用程序不支持,对较旧的 CPU 禁用 Target Architectures


在 Quality 设置中,禁用不需要的质量级别。


  禁用不必要的物理设置


如果游戏不使用物理设置,请取消选中 Auto SimulationAuto Sync Transforms。否则它们会降低应用程序运行速度,却并无任何可见的好处。


  选择正确的帧率


移动端项目必须在帧率和电池续航时间以及热节流之间获得平衡。不需要将设备限值推向 60 fps,可以折衷以 30 fps 运行。Unity 默认移动端为 30 fps。


您也可以通过 Application.targetFrameRate 在运行时动态调整帧率。例如,您甚至可以将缓慢或相对静止的场景降至 30 fps 以下,而将玩游戏时的 fps 设置保留为较高值。


  避免使用过多层级


拆分层级!在层级视图中如果游戏对象不需要嵌套,请简化父子化。较少的层级关系将受益于多线程刷新场景中的变换 (Transform)。复杂层级关系会发生不必要的变换 (Transform) 计算以及更多垃圾收集开销。


请参阅优化层级关系点击回看)和此 Unite 报告了解变换 (Transform) 的最佳实践。


Unite 报告:

https://www.youtube.com/watch?v=W45-fsnPhJY&t=794s


  变换一次,而非两次


外,移动变换 (Transform) 时,使用 Transform.SetPositionAndRotation 可以一次就同时更新位置和旋转。这样可以避免两次修改变换(Transform)的开销。


Transform.SetPositionAndRotation:

https://docs.unity3d.com/ScriptReference/Transform.SetPositionAndRotation.html


如果需要在运行时初始化游戏对象,一项简单的优化是在初始化过程中父子化和重新定位:


初始化游戏对象:

https://docs.unity3d.com/ScriptReference/Object.Instantiate.html


GameObject.Instantiate(prefab, parent);GameObject.Instantiate(prefab, parent, position, rotation);


有关 Object.Instantiate 的更多详细信息,请参阅脚本 API。


脚本 API:

https://docs.unity3d.com/ScriptReference/Object.Instantiate.html


  假设 Vsync 已启用


移动平台不渲染半帧。即使在编辑器中禁用 Vsync (Project Settings > Quality), Vsync 在硬件级别也处于启用状态。如果 GPU 无法足够快地刷新,将保持当前帧,从而有效降低每秒帧数。


资源


资源管线可以大幅影响应用程序的性能。经验丰富的技术美术师可以帮助您的团队定义和增强资源格式、规范以及导入设置。


不要依赖于默认设置。使用平台特定的覆盖选项卡可以优化纹理和网格几何体等资源。如果设置不正确,则可能造成较大的编译版本大小、较长的构建时间,以及较差的内存使用量。可以考虑使用预设功能来帮助为特定项目自定义基准设置,以确保最优设置。


请参阅此艺术资源最佳实践指南了解更多详细信息,或者在 Unity Learn 上了解有关适用于移动应用程序的 3D 美术优化的课程。


艺术资源最佳实践指南:

https://docs.unity3d.com/cn/current/Manual/ImportingAssets.html


Unity Learn 上的课程:

https://learn.unity.com/course/arm-he-unity-lian-he-tui-chu-gua-yong-yu-yi-dong-ying-yong-cheng-xu-de-3d-mei-zhu-you-hua

  正确导入纹理


纹理会占用大部分内存,因此,导入设置非常重要。通常,请遵循以下指导原则 :


 减小 Max Size:使用能生成视觉上可接受的结果的最低设置。这种非破坏性方式,可以快速降低纹理内存。


 使用 2 的幂 (POT) :Unity 要求移动端纹理压缩格式(PVRCT 或 ETC)采用 POT 纹理尺寸。


 制作纹理图集:将多个纹理放置到单个纹理中,可以减少绘制调用和加快渲染速度。使用 Unity 精灵图集或第三方 Texture Packer 可以制作纹理图集。


Unity 精灵图集:

https://docs.unity3d.com/cn/current/Manual/class-SpriteAtlas.html


Texture Packer:

https://www.codeandweb.com/texturepacker


 关闭 Read/Write Enabled 选项:如果启用,此选项在 CPU 和 GPU 可寻址内存中都会创建副本,纹理会占用双倍内存。大多数情况下,应保持此选项为禁用状态。如果要在运行时生成纹理,请通过 Texture2D.Apply 强制执行,并且传入设置为 true 的 makeNoLongerReadable。


 禁用不必要的 Mip Map:对于在屏幕上大小保持不变的纹理(如 2D 精灵和 UI 图形),Mip Map 不是必需的,对于与摄像机的距离会变化的 3D 模型,请保留 Mip Map 为启用状态。


正确的纹理导入设置有助于优化版本大小

  压缩纹理


考虑以下使用相同模型和纹理的两个实例。左侧的设置几乎使用右侧设置八倍的内存量,但并没有改善视觉质量。


未压缩的纹理需要更多内存


对 iOS 和 Android 都使用自适应可伸缩纹理压缩 (ATSC)。绝大多数开发目标最低规格设备游戏都支持 ATSC 压缩。


唯一的例外是 :


 适用于面向 A7 设备或更低规格的 iOS 游戏(例如 iPhone 5、5S 等)— 使用 PVRTC


 适用于面向 2016 之前的设备的 Android 游戏 — 使用 ETC2(Ericsson 纹理压缩)


如果压缩格式(如 PVRTC 和 ETC)的质量不够高,并且目标平台不完全支持 ASTC,请尝试采用 16 位纹理而不是 32 位纹理。


请参阅以下手册了解有关各平台的推荐纹理压缩格式的更多信息。

https://docs.unity3d.com/cn/current/Manual/class-TextureImporterOverride.html


  调整网格导入设置


与纹理很像,如果导入时不小心,网格可能占用过多内存。要尽可能减少网格占用的内存,请执行以下操作 :


 压缩网格:高性能压缩可以减少占用磁盘空间(但不会影响运行时的内存)。请注意,网格量化可能造成不准确,因此应试验不同的压缩级别,从而找到适合模型的压缩级别。


 禁用 Read/Write:如果启用此选项,内存中会有重复网格,网格的一个副本在系统内存中,另一个在 GPU 内存中。大多数情况下,应将其禁用(在 Unity 2019.2 以及更早版本中,此选项默认为选中状态)。


 禁用骨骼和 BlendShape:如果网格不需要骨架或 BlendShape 动画,请尽可能禁用这些选项。


尽可能禁用法线和切线:如果确信网格的材质不需要法线或切线,请取消选中这些选项,以节省更多内存。


检查网格导入设置


  检查多边形数量


分辨率越高的模型,需要的内存使用量越大,并且可能占用更长的 GPU 时间。您的背景几何体是否需要五十万个多边形?考虑减少所选 DCC 包中的模型。删除摄像机的视角看不到的多边形。使用纹理和法线贴图而不是高密度网格来实现精细的细节。


  使用 AssetPostprocessor 自动执行导入设置


利用 AssetPostprocessor 可以在导入资源时运行脚本。这样,您可以在导入模型、纹理、音频等之前和 / 或之后对设置进行自定义。


AssetPostprocessor:

https://docs.unity3d.com/ScriptReference/AssetPostprocessor.html


  使用可寻址资源系统


可寻址资源系统提高一种简化的方法来管理内容,按“地址”或别名加载资源包。这种统一的系统从本地路径或远程内容分发网络 (CDN) 执行异步加载。


可寻址资源系统:

http://docs.unity3d.com/Packages/com.unity.addressables@1.18/manual/index.html



如果将非代码资源(模型、纹理、预制件、音频,甚至整个场景)拆分为资源包,则可以将它们分为可下载内容 (DLC)。


资源包:

https://docs.unity3d.com/cn/current/Manual/AssetBundlesIntro.html


然后,使用 Addressables 为移动端应用程序创建较小的初始构建版本。云端资源分发可承载您的游戏内容并随着玩家的游戏进展将内容分发至玩家。


云端资源分发:

https://unity.cn/product/cloud-content-delivery


使用可寻址资源系统按“地址”加载资源


通过以下链接,查看可寻址资源系统如何简化资源管理。

https://unity.com/cn/how-to/simplify-your-content-management-addressables


图形和 GPU 优化


每一帧,Unity 都需要确定必须渲染哪些对象,然后创建绘制调用。绘制调用是调用图形 API 来绘制对象(如三角形),而批处理是要一起执行的一组绘制调用。


随着项目变得更加复杂,您需要用管线来优化 GPU 的工作负载。通用渲染管线 (URP) 目前使用单通道前向渲染器将高质量图形传输给移动平台(未来版本中将提供延迟渲染功能)。来自游戏主机和 PC 的、基于物理的光照和材质也可以缩放为适合手机或平板电脑。


以下指导原则可以帮助您提高图形处理速度。


  批处理执行绘制调用


将要绘制的对象组合为批次,可以尽可能减少在批次中绘制每个对象所需的状态更改。这种方式通过减少渲染对象的 CPU 开销,可以改善性能。Unity 可以使用以下几种方法将多个对象组合为较少的批次 :


 动态批处理:对于小网格,Unity 在 CPU 上分组和转换顶点,然后一次性绘制它们。注意:只在有足够低复杂度网格(少于 900 个顶点属性和不超过 300 个顶点)时使用这一方法。动态批处理程序不会对更大的网格进行批处理,如果启用会浪费 CPU 时间在每一帧都去查找要批处理的小网格。


 静态批处理:对于不移动的几何体,Unity 可以减少所有共享相同材质的网格的绘制调用。它比动态批处理更有效,但使用更多内存。


 GPU 实例化:如果有大量相同的对象,这种方法通过图像硬件对它们进行更有效地批处理。


 SRP 批处理:在 Advanced 下面的 Universal Render Pipeline Asset 中启用 SRP Batcher。这样可以大幅提高 CPU 渲染速度,具体取决于场景。


组织游戏对象,以便利用这些批处理方法

  使用帧调试器 (Frame Debugger)


帧调试器介绍每一帧是如何通过各绘制调用构建的。这是非常重要的工具,可以解决着色器属性问题,帮助您分析游戏渲染方式。


帧调试器:
https://docs.unity3d.com/cn/current/Manual/FrameDebugger.html


帧调试器将每一帧分到不同的步骤中



完整版《移动游戏优化指南》汇集了 Unity 软件工程师专家团队的知识和建议,尽在 Unity 中文课堂,点击“阅读原文”即可跳转。
https://learn.u3d.cn/tutorial/mobile-game-optimization





长按关注

Unity 官方微信

第一时间了解Unity引擎动向,学习最新开发技巧




 点击“阅读原文”,跳转Unity中文课堂 


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存