资产审计(Asset auditing)
临时的“测试”更改和疲惫的开发人员的错误点击可能会默默地添加性能较差的资产,或者更改现有资产的导入设置。对于任何规模较大的项目,最好有第一道防御人为错误的防线。编写一小段代码,确保没有人可以在项目中添加4K未压缩纹理,这是相对简单的。
然而,这是一个令人惊讶的普遍问题。4K未压缩纹理占用60兆内存。在低端移动设备(如iPhone 4S)上,消耗超过180 - 200mb的内存是危险的。如果错误地添加,这个Texture会不经意地占用应用程序内存预算的三分之一到四分之一,并导致难以诊断的内存不足错误。
虽然现在可以使用 5.3 Memory Profiler,跟踪这些问题,但最好首先确保不可能出现此类错误。
AssetPostprocessor
可以在导入资产时接收回调,用于强制执行某些最低标准。
从 AssetPostprocessor 继承并实现一个或多个OnPreprocess方法。重要的包括:
OnPreprocessTextureOnPreprocessModelOnPreprocessAnimationOnPreprocessAudio
更多OnPreprocess方法:https://docs.unity3d.com/2019.4/Documentation/ScriptReference/AssetPostprocessor.html
1 |
|
Common Asset rules
Textures
- Disable the read/write enabled flag
Read/Write 启用标志导致纹理在内存中保留两次:一次在GPU上,一次在CPU可寻址内存。(注意:这是因为在大多数平台上,从GPU内存回读非常慢。从GPU内存中读取纹理到CPU代码(例如纹理)使用的临时缓冲区。Texture.GetPixel)将非常不高效。在Unity中,这个设置在默认情况下是禁用的,但它可以意外地打开。
Read/Write 启用标志仅在Shader之外操作纹理数据时才需要(例如Texture.GetPixel和Texture.SetPixel),应该尽可能避免。
- Disable Mipmaps if possible
对于相对于相机具有相对不变的 Z-depth 的对象,可以禁用mipmaps以节省加载纹理所需内存的三分之一。如果一个对象改变了 Z-depth,禁用 mipmaps 会导致GPU上的纹理采样性能变差。
一般来说,这对于UI纹理和其他在屏幕上以恒定大小显示的纹理是有用的。
- Compress all Textures
使用适合项目目标平台的纹理压缩格式对于节省内存至关重要。如果选择的纹理压缩格式不适合目标平台,Unity将在加载纹理时解压缩纹理,这将消耗CPU时间和过多的内存。这是Android设备上最常见的问题,因为Android设备通常根据芯片组的不同支持不同的纹理压缩格式。
- Enforce sensible Texture size limits
虽然这很简单,但也很容易忘记调整纹理大小或无意中更改纹理大小导入设置。为不同类型的纹理确定一个合理的最大尺寸,并通过代码强制执行。对于许多移动应用程序,2048×2048或1024×1024足以用于纹理 Atlas,而512×512足以用于3D模型的纹理。
Models
- Disable the Read/Write enabled flag
Read/Write 启用标志与Texture的操作相同。然而,它在默认情况下是为 Model 启用的。
如果项目在运行时通过脚本修改 Mesh,或者 Mesh 被用作MeshCollider组件的基础,Unity需要启用此标志。如果模型没有在 MeshCollider 中使用,也没有被脚本操作,禁用这个标志可以节省一半的模型内存。
- Disable rigs on non-character models
默认情况下,Unity为非角色模型导入一个通用 rig 。如果在运行时实例化模型,这将导致添加 Animator 组件。如果模型不是通过 Animation system 动画化的,这就给动画系统增加了不必要的开销,因为所有活动的 Animator 必须每帧tick一次。
禁用非动画模型上的 rig ,以避免自动添加 Animator 组件和可能无意中添加不需要的 Animator 到场景。
- Enable the Optimize Game Objects option on animated models
优化 Game Objects option 对动画模型有显著的性能影响。当该选项被禁用时,无论何时模型被实例化,Unity都会创建一个反映模型骨架结构的大型转换层次结构。这个转换层次结构的更新成本很高,特别是当其他组件(如Particle Systems或Colliders)附加到它时。这也限制了Unity多线程 Mesh skinning 和 bone animation 计算的能力。
如果需要暴露模型骨骼结构上的特定位置(例如为了动态附加武器模型而暴露模型的手),则可以在 Extra Transforms 列表中特别允许这些位置。
- Use Mesh compression when possible
启用 Mesh 压缩可以减少用于表示模型数据的不同通道的浮点数的 bit 数。这可能会导致精度的轻微损失,这种不精确的影响应该在最终项目中使用之前由美工检查。
压缩级别使用的特定 bit 数在ModelImporterMeshCompression脚本参考中有详细说明:https://docs.unity3d.com/ScriptReference/ModelImporterMeshCompression.html
请注意,对于不同的通道可以使用不同的压缩级别,因此项目可以选择只压缩切线和法线,而不压缩uv和顶点位置。
- Note: Mesh Renderer Settings
当将 Mesh Renderer 添加到 Prefab 或 GameObject 时,请注意组件上的设置。默认情况下,Unity启用阴影投射和接收(Shadow )、光探测采样(Light Probe)、反射探测采样(Reflection Probe)和运动矢量计算(Motion Vector)。
如果项目不需要这些特性中的一个或多个,请确保通过自动化脚本关闭它们。任何添加MeshRenderers的运行时代码也需要切换这些设置。
对于2D游戏,在打开 shadow 选项的场景中添加 MeshRenderer 会在 rendering loop 中添加一个完整的阴影通道。这通常是对性能的浪费。
Audio
- Platform-appropriate compression settings
启用与可用硬件匹配的音频压缩格式。所有iOS设备都包含硬件MP3解压缩器,许多Android设备本身也支持Vorbis。
此外,将未压缩的音频文件导入Unity。Unity总是在构建项目时重新压缩音频。没有必要导入压缩音频,然后重新压缩它;这只会降低最终 audio clip 的质量。
- Force audio clips to mono
很少有移动设备有立体扬声器。在移动项目中,将导入的音频片段强制为单通道可以减少内存消耗。此设置也适用于任何没有立体声效果的音频,例如大多数UI音效。
- Reduce audio bitrate
虽然这需要咨询音频设计师,但要尽量减少音频文件的比特率,以进一步节省内存消耗和构建项目规模。