现实项目中发现的大多数问题都是由于一些诚实的错误造成的——疲惫的开发者可能会在项目中默默地添加一些性能不佳的资源或更改现有资源的导入设置,这些都是暂时的“测试”更改或误操作。
对于任何规模较大的项目,最好设置第一道防线来抵御人为错误。写一小段代码来确保没有人可以将 4K 未压缩纹理添加到项目中,这相对来说比较简单。
然而,这却是一个出奇常见的问题。一个 4K 未压缩纹理占用 60 兆字节的内存。在像 iPhone 4S 这样的低端移动设备上,消耗超过 180-200 兆字节的内存是十分危险的。如果不小心添加了这个纹理,它会无意中占用应用程序内存预算的三分之一到四分之一,并导致难以诊断的内存不足错误。
虽然现在可以使用 5.3 内存 探查器一个帮助你优化游戏的窗口。它显示了你游戏各个区域所花费的时间。例如,它可以报告渲染、动画或游戏逻辑所花费的时间百分比。 更多信息
参见 词汇表 来追踪这些问题,但最好是能够从一开始就防止此类错误的发生。
Unity 编辑器中的 AssetPostprocessor
类可以用来对 Unity 项目强制执行一些最低标准。这个类在资源导入时会收到回调。要使用它,请继承自 AssetPostprocessor
并实现一个或多个 OnPreprocess
方法。重要的方法包括:
OnPreprocessTexture
OnPreprocessModel
OnPreprocessAnimation
OnPreprocessAudio
有关更多可能的 OnPreprocess
方法,请参阅脚本参考中的 AssetPostprocessor。
public class ReadOnlyModelPostprocessor : AssetPostprocessor {
public void OnPreprocessModel() {
ModelImporter modelImporter =
(ModelImporter)assetImporter;
if(modelImporter.isReadable) {
modelImporter.isReadable = false;
modelImporter.SaveAndReimport();
}
}
}
这是一个简单的 AssetPostprocessor
示例,它对项目强制执行规则
每当模型导入项目或模型的导入设置发生更改时,都会调用此类。这段代码只需检查 读/写启用
标志(由 isReadable
属性表示)是否设置为 true
。如果设置为 true
,则会将该标志强制设置为 false
,然后保存并重新导入资源。
请注意,调用 SaveAndReimport
会导致再次调用这段代码!但是,由于现在已确定 isReadable
为 false,因此此代码不会产生无限的重新导入循环。
这种更改的原因将在下面的“模型”部分中进行讨论。
禁用读/写启用标志
读/写启用
标志会导致纹理在内存中保存两次:一次在 GPU 上,一次在 CPU 可寻址内存中 (1)(注意:这是因为,在大多数平台上,从 GPU 内存读取速度非常慢。从 GPU 内存读取纹理到 CPU 代码(例如 Texture.GetPixel)使用的临时缓冲区将非常低效)。在 Unity 中,此设置默认情况下是禁用的,但可能会被意外地启用。
仅在 着色器在 GPU 上运行的程序。 更多信息
参见 词汇表 外部操作纹理数据(例如使用 Texture.GetPixel
和 Texture.SetPixel
API)时才需要 读/写启用
,应尽可能避免使用它。
尽可能禁用 Mipmaps
对于相对于 相机一个组件,它会创建场景中特定视点的图像。输出要么绘制到屏幕上,要么作为纹理捕获。 更多信息
参见 词汇表 的 Z 深度相对不变的对象,可以禁用 mipmaps 以节省大约三分之一的纹理加载所需的内存。如果对象的 Z 深度发生变化,则禁用 mipmaps 会导致 GPU 上的纹理采样性能更差。
通常,这对于 UI(用户界面) 允许用户与应用程序交互。Unity 目前支持三种 UI 系统。 更多信息
参见 词汇表 纹理和其他以固定大小显示在屏幕上的纹理很有用。
压缩所有纹理
使用适合项目目标平台的纹理 压缩一种存储数据的方法,可以减少其所需的存储空间。参见 纹理压缩、动画压缩、音频压缩、构建压缩。
参见 词汇表 格式对于节省内存至关重要。
如果选择的 纹理压缩3D 图形硬件要求纹理以专门的格式压缩,这些格式针对快速纹理采样进行了优化。 更多信息
参见 词汇表 格式不适合目标平台,Unity 会在纹理加载时解压缩纹理,从而消耗 CPU 时间和大量的内存。这在 Android 设备上最常出现问题,因为它们通常支持不同的纹理压缩格式,具体取决于芯片组。
强制执行合理的纹理大小限制
虽然这很简单,但也很容易忘记调整纹理大小或无意中更改纹理大小导入设置。确定不同类型纹理的合理最大大小,并通过代码强制执行这些限制。
对于许多移动应用程序来说,2048x2048 或 1024x1024 足以用于纹理图集,而 512x512 足以用于应用于 3D 模型的纹理。
禁用读/写启用标志
模型的 读/写启用
标志与纹理中描述的标志相同。但是,它在模型中默认情况下是启用的。
如果项目在运行时通过脚本修改 网格Unity 的主要图形基元。网格构成了你 3D 世界的很大一部分。Unity 支持三角形或四边形多边形网格。NURBS、NURMS、细分曲面必须转换为多边形。 更多信息
参见 词汇表,或者如果网格用作 MeshCollider 组件的基础,则 Unity 需要启用此标志。如果模型没有在 MeshCollider 中使用,并且没有被 脚本一段代码,允许你创建自己的组件、触发游戏事件、随时间推移修改组件属性以及以你喜欢的任何方式响应用户输入。 更多信息
参见 词汇表 操作,请禁用此标志以节省模型一半的内存。
在非角色模型上禁用绑定
默认情况下,Unity 会为非角色模型导入一个通用绑定。如果在运行时实例化模型,这会导致添加 Animator
组件。如果模型不是通过动画系统进行动画处理的,这会给动画系统增加不必要的开销,因为所有活动的 Animator 必须在每帧进行一次计时。
在非动画模型上禁用绑定,以避免自动添加 Animator 组件模型上的一个组件,使用动画系统对该模型进行动画处理。该组件引用一个 Animator 控制器资源,该资源控制动画。 更多信息
参见 词汇表,并且可能无意中将不需要的 Animator 添加到 场景一个场景包含你的游戏环境和菜单。可以将每个唯一的场景文件视为一个独特的关卡。在每个场景中,你放置环境、障碍物和装饰,实际上是将游戏设计并构建成碎片。 更多信息
参见 词汇表。
在动画模型上启用优化游戏对象选项
优化游戏对象 选项对动画模型具有显著的性能影响。当禁用此选项时,Unity 会在实例化模型时创建一个大型变换层次结构,该层次结构反映模型的骨骼结构。此变换层次结构的更新成本很高,尤其是在将其他组件(如粒子系统或碰撞体)附加到它时。它还会限制 Unity 对网格 蒙皮将骨骼关节绑定到角色网格或“蒙皮”顶点的过程。使用外部工具执行,例如 Blender 或 Autodesk Maya。 更多信息
参见 词汇表 和骨骼动画计算进行多线程处理的能力。
如果需要公开模型骨骼结构中的特定位置(例如,公开模型的手部以动态附加武器模型),则可以在 额外变换
列表中专门允许这些位置。
有关更多详细信息,请参阅 Unity 手册页面上的 模型导入器。
尽可能使用网格压缩
启用网格压缩会减少用于表示模型数据的不同通道的浮点数所需的位数。这会导致轻微的精度损失,应在最终项目中使用之前由艺术家检查这种精度损失的影响。
特定压缩级别使用的位数在 ModelImporterMeshCompression 脚本参考中进行了详细说明。
请注意,可以对不同的通道使用不同的压缩级别,因此项目可以选择仅压缩切线和法线,而保持 UV 和顶点位置未压缩。
注意:网格渲染器一个网格组件,它从网格过滤器获取几何图形,并在对象变换组件定义的位置对其进行渲染。 更多信息
参见 词汇表 设置
当您向 预制体一种资产类型,允许您存储包含组件和属性的完整游戏对象。预制体充当模板,您可以从该模板在场景中创建新的对象实例。 更多信息
参见 术语表 或 游戏对象Unity 场景中的基本对象,可以代表角色、道具、场景、相机、路点等。游戏对象的功能由附加到它的组件定义。 更多信息
参见 术语表 添加网格渲染器时,请注意组件上的设置。默认情况下,Unity 启用了阴影投射和接收、光探针光探针存储有关光线如何穿过场景中的空间的信息。在一给定空间内排列的光探针集合可以改善该空间内移动物体和静态 LOD 场景的照明。 更多信息
参见 术语表 采样、反射探针一种渲染组件,它捕获周围环境的球形视图,类似于相机。捕获的图像随后存储为立方体贴图,可供使用反射材质的对象使用。 更多信息
参见 术语表 采样和运动矢量计算。
如果项目不需要这些功能中的一个或多个,请确保通过自动化脚本将其关闭。任何在运行时添加网格渲染器的代码也需要切换这些设置。
对于 2D 游戏,意外地将网格渲染器添加到场景中,并且阴影选项已开启,会为渲染循环添加完整的阴影通道。这通常会浪费性能。
平台合适的压缩设置
启用与可用硬件匹配的音频压缩格式。所有 iOS 设备都包含硬件 MP3 解压缩器,并且许多 Android 设备原生支持 Vorbis。
此外,将未压缩的音频文件导入 Unity。Unity 在构建项目时始终会重新压缩音频。无需导入压缩音频然后重新压缩它;这样做只会降低最终 音频片段Unity 中音频数据的容器。Unity 支持单声道、立体声和多声道音频资产(最多八个声道)。Unity 可以导入 .aif、.wav、.mp3 和 .ogg 音频文件格式,以及 .xm、.mod、.it 和 .s3m 跟踪模块格式。 更多信息
参见 术语表 的质量。
强制音频片段为单声道
很少有移动设备实际具有立体声扬声器。在移动项目中,强制导入的音频片段为单声道会将其内存消耗减半。此设置也适用于没有立体声效果的任何音频,例如大多数 UI 音效。
降低音频比特率
虽然这需要与音频设计师协商,但尝试最小化音频文件的比特率,以进一步节省内存消耗和构建项目的体积。