Unity性能优化(资源篇)

前言

        本篇文章是对《Unity性能优化》视频内容的整理。我仅仅收录了我认为对且比较有用的内容,因此我仍然建议你去看原视频。或许你的观点和我不一样。为了文章篇幅,本文仅仅只对资源方面的优化进行介绍,对应参考视频中第壹集(第一集)到第伍集(第五集)的内容。

音频

        音频一般不是性能优化的重点,但是我们仍然可以从中减少一些性能上的消耗。下面是音频设置的图片:

下面的preview窗口中,你会发现有ch1和ch2。这表示这是一个双声道的音频,如果这两个声道的音频差不多,则使用双声道就没必要了,我们可以开启Force To Mono将其改为单声道。此举在内容不丢失的情况下,我们可以减少其使用的内存和大小。尤其是在移动平台中,我们几乎听不出区别。关于如何判断两个声道的音频差不多,则需要使用专业的软件来判断了。如果你觉得双声道没必要,那也可以通过这个操作改为单声道,具体还要看项目的需求,但是这样可能会导致声音错误。除了双声道外,Unity最多支持八声道音频。这些我们都可以开启Force To Mono将其改为单声道。Force To Mono下还有一个子功能:Normalize,开启此功能音频会在混合过程中被标准化。这个我认为要视具体表现而定。

        除了音频的大小影响我们加载的速度,音频的加载方式也同样对加载速度有影响。图中的Load Type就是音频加载的类型。Unity官方一共提供了三种加载方式。

  1. Decompress On Load:音频文件加载后将立即解压缩。
  2. Compressed In Memory:声音在内存中保持压缩状态,播放时解压缩。
  3. Streaming:即时解码声音。

对于这三种不同的加载方式,官方都有对应的推荐和注意事项。

Decompress On Load,请对小的压缩过的声音使用此选项,以避免动态解压缩产生性能开销。请注意,在加载时解压缩 Vorbis 编码的声音所使用的内存量是保持压缩状态时内存使用量的 10 倍(ADPCM 编码约为 3.5 倍),因此请勿对大文件使用此选项。`Decompress On Load`是Unity默认的音频加载方式。

Compressed In Memory,此选项具有轻微的性能开销(特别是对于 Ogg/Vorbis 压缩文件),因此仅应当将其用于较大的文件(此情况下,加载时解压缩将使用大量的内存)。解压缩发生在混音器线程中,可在性能分析器窗口的音频面板中的“DSP CPU”部分对其进行监控。

Streaming,此方法使用最少量的内存来缓冲从磁盘中逐渐读取并即时解码的压缩数据。请注意,解压缩发生在单独的串流线程上;可在性能分析器窗口的音频面板中的“Streaming CPU”部分监控其 CPU 使用率。注意:即使没有加载任何音频数据,串流剪辑也有大约 200KB 的过载量。

Decompress On Load这个选项一般是压缩后大小小于200kb的音效文件,如果大于这个值则使用Compressed In Memory。如果是背景音乐或者较长较大的音效则用Streaming。

        一般情况下,我们最好使用.wav格式的音频。因为这个是无压缩的音频文件格式,Unity本身就会对音频文件进行压缩Compression Format就是用来指定压缩的格式。Unity支持在不同平台下指定不同的压缩方式,平台不同对压缩方式的支持也各不相同。这个需要针对不同的平台做调查和对应的压缩方式的修改。Unity官方一共提供了三种压缩的方式。

  1. PCM:此选项提供高质量,代价是文件内存变大,适合内存小的声音效果。
  2. ADPCM:此格式适用于大量噪音和需要大量播放的声音(例如脚步声、撞击声、武器声音)。较之于 PCM,压缩能力提高 3.5 倍,但 CPU 使用率远低于 MP3/Vorbis 格式,因此成为上述声音类别的最佳压缩方案。
  3. Vorbis/MP3:压缩使文件减小,但与 PCM 音频相比,质量降低。可通过 Quality 滑动条来配置压缩量。此格式最适合中等长度的音效和音乐。

        默认情况下,Unity是使用Vorbis压缩。除了上面的说明,我们还需要注意一些事情。有些平台下是不提供Mp3压缩的。IOS平台对Mp3格式的支持比较好,如果音频不需要循环播放且平台支持可以使用Mp3格式。一些较短的音效使用ADPCM加载会更快一些,因为其播放过程中解码快,但是其压缩比就不太行。对于压缩方式的选择,我们结合音频在项目中的作用来进行选择。

        我们还需要注意音频原文件的采样率。已上图为例,在preview窗口中,我们可以看到其采样率是48000Hz。如果是在移动平台上,这样的采样率是没必要的。一般移动平台就设定为22050Hz就好了,请注意这个是一个经验值。随着后面移动平台发展,这个值或许会出现变化。具体的值最好还是取决于其表现。

        关于音频更多的设定可以查阅官方提供的文档。

模型资源

        如果你的团队有对应的建模师。那么在美术导出资源的时候,我们也需要在美术上做一些规范。

  • 统一单位

  • 导出的网格必须是多边形拓扑,不能是贝塞尔曲线、样条曲线、细分曲面等

  • 在导出之前确保所有Deformers都烘培到网格模型上

  • 不建议模型使用的纹理随模型导出

  • 如果需要导入Blend shape normals时,必须指定光滑组Smooth groups

  • 建议导出时不携带如摄像机、灯光、材质等场景信息。

符合规范的模型在导入Unity时可以减少冗余信息,可以在一定程度减少性能上的消耗。作为客户端,我们只能对模型导入的设置进行一些修改,该达到性能优化的目的。

        模型导入设置一共有四个选项:模型 (Model) 选项卡,骨架 (Rig) 选项卡,动画 (Animation) 选项卡,材质 (Materials) 选项卡。这四个选项卡在Unity官方的技术文档中都有详细的介绍。这里也不会逐一介绍,我只针对可以做优化的点上进行。事先说明,对于模型设置的修改在优化上并没有太大的效果。视频中的测试也是如此。所以如果你嫌麻烦直接按照unity的默认设置就可以了。

模型 (Model) 选项卡:

        模型选项卡可以被分成三个部分:场景(Scene)、网格(Meshes)和几何(Geometry)。这里我并不会说明所有的属性,如果要查看所有的属性的意义,可以查阅Unity的官方文档。

        场景(Scene):

1. 一般情况下,我们不需要模型自带的一些灯光,相机等信息。因此,我们可以将Import Cameras(导入相机),Import Lights(导入灯光)取消勾选。

2. Import Visibility(导入可见性),这个要看你具体的需求,一般也是取消勾选的。

3. 同样Import BlendShapes(导入混合形状)也是如此。在我找到的资料中说Blend Shape(Unity中的叫法,UE称为Morph Target)本质上是一组顶点偏移数据:模型有一个基础形状,每个 Blend Shape 记录一批顶点相对基础形状的位置偏移;运行时用权重进行插值。如果你的动画没有使用到,或者说不需要使用到,那就可以取消勾选。

        网格(Meshes):

1. Mesh Compression字面意思,它可以对网格进行压缩。压缩后的网格会减少存储,但是并不会减少内存。如果需要压缩游戏体积,那么可以开启此选项。

2. Read/Write Enabled,启用此选项时,Unity 会将网格数据上传到 GPU 可寻址内存,但也会将其保存在 CPU 可寻址内存中。这意味着 Unity 可以在运行时访问网格数据,您也可以从脚本中访问网格数据。默认情况下会禁用此选项。在大多数情况下,为节省运行时内存使用量,请将此选项置为禁用状态。

3. Generate Colliders,启用此属性可在自动附加网格碰撞体的情况下导入您的网格。这可以用于为环境几何体快速生成碰撞网格。如果你没有这个需求,那么最好取消勾选。

       几何(Geometry):

1. Index Format,定义网格索引缓冲区的大小。它有三个选择:

    Auto,在导入网格时,让 Unity 根据网格顶点数来决定是使用 16 位索引还是 32 位索引。对于 Unity 2017.3 和更高版本中添加的资源,这是默认设置。

    16 bit,导入网格时使用 16 位索引。如果网格较大,则会将其分割为小于 64k 的顶点块。对于在 Unity 2017.2 或更低版本中建立的项目,这是默认设置。

    32 bit,导入网格时使用 32 位索引。如果使用的是基于 GPU 的渲染管线(例如,使用计算着色器三角形剔除),那么使用 32 位索引将确保所有网格使用相同的索引格式。这降低了着色器的复杂性,因为它们只需要处理一种格式。

一般而言,我们只要让Unity自己去选择就好了。但是如果你要更可控一点,那你就可以按照需求修改。

2. Tangents(切线),定义如何导入或计算顶点切线。它有三个选择:

    Import,从对应的文件中导入。

    Calculate Legacy - Split Tangent,使用旧版算法计算切线,并在 UV 图表上进行拆分。如果网格上的接缝破坏了法线贴图光照,请使用此属性。此属性通常仅适用于角色。

    None,不导入顶点切线。网格没有切线,因此将无法使用法线贴图着色器。

如果你确定用不到切线,那么你可以直接设置为None,这也能缩小体积。

骨架 (Rig) 选项卡

        骨骼选项卡,我们可以改动的地方不多。如果你确定要使用骨骼,那么你就要按照动画类型去正确配对你的骨骼。如果你不需要动画,那么直接将其设置为None就好了。更多信息,我放在了动画部分说明,包括没有说到的Animation选项卡。

材质 (Materials) 选项卡

        材质 (Materials) 选项卡,我们可以改动的地方不多。如果你模型的材质都是用自己的,那么你可以将Material Creation Mode设置为None。

额外的设置

        除了上面这显而易见的地方,实际上还有一些地方也会影响到模型的导出。

        在 (Edit) > 项目设置 (Project Settings) > 播放器 (Player)中我们可以找到一个名为“顶点压缩”(Vertex Compression)的设置。在官方文档中是这么描述的:Unity 默认会压缩这些通道(Normal,Tangent,Tex Coord 0,Tex Coord 2,Tex Coord 3),因为在大多数情况下,这种设置组合可以很好地节省内存,同时不会大幅改变网格的外观。默认情况下,Unity 不会压缩其他设置(Position 和 Tex Coord 1),因为这些设置更有可能影响网格的外观,并且不会显著减少内存使用量。如果您打算对 Position 和 Tex Coord 1 通道启用顶点压缩,则应测试这些设置,确保它们不会在网格中产生瑕疵。

        优化网格数据(Optimize Mesh Data)设置就在“顶点压缩”,Unity并没有对其有单独的文档(或许有,但是我找不到)。它被写入到了对Player设置的描述中。其描述大体意思如下:启用此选项可从用于构建的网格中移除未使用的顶点属性。此功能可减少网格数据量,从而有助于减小构建文件大小、缩短加载时间以及降低运行时内存占用。官方还留下了一个警告:如果启用此选项,请勿在运行时更改材质或着色器设置。

纹理资源

        纹理资源是优化中的重点。但是其本身知识也比较杂,本小节除了介绍如何优化外,也会介绍一些纹理相关的知识点。

知识点

纹理类型

  1. Default(默认):默认的纹理类型格式。绝大多数资源都会采用这样的模式。

  2. Normalmap(法线贴图):法线贴图,可将颜色通道转换为适合实时法线贴图格式。

  3. Editor GUI and Legacy GUI(编辑器 GUI 和 旧版 GUI):在编辑器GUI控件上使用纹理请选择此类型。一般在性能优化上不会考虑,因为他们几乎不会被游戏逻辑或者是资产使用到,因此打包后这些资源并不能放到游戏中。我们自然就不用考虑这些资源的优化了。

  4. Sprite(2D and UI)(精灵):在2D游戏中使用的精灵(Sprite)或UGUI使用的纹理请选择此类型。

  5. Cursor(光标):鼠标光标自定义纹理类型。

  6. Cookie(剪影):其会格式化纹理资源,用于光照Cookie剪影类型的纹理。

  7. Lightmap(光照贴图):光照贴图类型的纹理,其会格式化纹理资源,编码格式取决于不同的平台。

  8. SingleChannel(单通道):其会格式化纹理资源,使其只有一个通道。如果你只需要原始图片文件的一个通道信息,请选择此类型。

  9. Directional Lightmap(方向光照贴图):其会格式化纹理资源,用作方向光照贴图。

  10. Shadowmask(阴影遮罩):其会格式化纹理资源,用作阴影遮罩。

纹理大小

        纹理可以使用不同大小的尺寸,但是一般现代显卡对纹理的大小支持都采用2的幂次方。比如说1024 x 1024,512 x 1024, 2048 x 2048。纹理大小不一定需要长宽一致,只要长宽大小是2的幂次方。

纹理压缩

        纹理压缩是指图像压缩算法,保持贴图视觉质量的同时,尽量减小纹理数据的大小。默认情况下我们的纹理原始格式采用PNG或TGA这类通用文件格式,但与专用图像格式相比他们访问和采样速度都比较慢,无法通用GPU硬件加速,同时纹理数据量大,占用内存较高。所以在渲染中我们会采用一些硬件支持的纹理压缩格式,如ASTC、ETC、ETC2、DXT等。

        不同平台和不同硬件对纹理压缩格式的支持程度不同,因此我们需要针对不同的平台和硬件去选择不同的纹理压缩格式。

纹理图集

        纹理图集是一系列小纹理图像的集合。它具有以下的优点:

  1. 采用共同纹理图集的多个静态网格资源可以进行静态合批处理,减少DrawCall调用次数。

  2. 纹理图集可以减少碎纹理过多,因为他们打包在一个图集里,这样可以更有效的利用纹理压缩,降低纹理的内存成本和冗余数据。

但是它也存着一些缺点:

  1. 美术需要合理规划模型,并且要求模型有相同的材质着色器,或需要制作通道图去区分不同材质。制作和修改成本较高。

纹理过滤

        我个人理解纹理过滤是指在渲染时,如何对纹理进行采样。即纹理过滤是在纹理采样时,对纹理进行插值计算的方法,以得到最终的纹理颜色值。纹理过滤的类型有以下几种:

  1. Nearest Point Filtering:临近点采样过滤最简单、计算量最小的纹理过滤形式,但在近距离观察时,纹理会呈现块状。

  2. Bilinear Filtering:双线性采样过滤会对临近纹素采样并插值化处理,对纹理像素进行着色。双线性过滤会让像素看上去平滑渐变但近距离观察时,纹理会变得模糊。

  3. Trilinear Filtering:三线性过滤除与双线性过滤相同部分外,还增加了Mipmap等级之间的采样差值混合,用来平滑过度消除Mipmap之间的明显变化。

  4. Anisotropic Filtering:各向异性过滤可以改善纹理在倾斜角度下的视觉效果,跟适合用于地表纹理。

Unity中只提供前三种方式。视频中提到的最后一种,我认为是纹理设置中的Aniso Level,Unity将其单独拎出来设置了。你可以在Unity官方文档中找到对应的描述。

Mipmap

        Mipmap:逐级减低分辨率来保存纹理副本。相当于生成了纹理LOD,渲染纹理时,将根据像素在屏幕中占据的纹理空间大小选择合适的Mipmap级别进行采样。它使得GPU不需要在远距离上对对象进行全分辨率纹理采样,因此可以提高纹理采样性能。同时也解决了远距离下的过采样导致的噪点问题,提高的纹理渲染质量。但是由于Mipmap纹理要生成低分辨率副本,因此会造成额外的内存开销。

优化方案思路

        纹理的大小会直接影响到内存和显存的占用大小。同时会对GPU纹理采样,CPU加载和带宽造成影响。所以首先我们要对纹理的大小进行抉择。这是最简单有效的优化方式。

        不同平台、不同硬件配置选择不同的纹理大小,Unity下可以采用bundle变体设置多套资源、通过Mipmap限制不同平台加载不同level层级的贴图。在不降低视觉效果的情况下尽量减小贴图大小,最好的方式是纹理映射的每一个纹素的大小正好符合屏幕上显示像素的大小,如果纹理小了会造成欠采样,纹理显示模糊,如果纹理大了会造成过采样纹理显示噪点。这一点做到完美很难保障,可以充分利用SceneView->DrawMode->Mipmap来查看在游戏摄像机视角下哪些纹理过采样,哪些纹理欠采样来调整纹理大小。在保证图片质量的情况下,你应该尽可能的选择相应平台下能被支持的纹理压缩格式。这个可以通过查阅各个平台下官方文档,或者是网上大家的经验来进行选择。现在这个时代可以可以通过AI来帮忙进行选择。同时你要注意尽量不能让美术人员通过增加纹理大小的方式增加细节,可以选择细节贴图DetailMap或增加高反差保留的方式。

        根据纹理用途的不同选择不同的纹理加载方式,如流式纹理加载Texture Streaming、稀疏纹理SparseTexture、虚拟纹理VirtualTexture等方式。

        默认大多数图像处理工具都会使用sRGB颜色空间处理和导出纹理。但如果你的纹理不是用作颜色信息的话,那就不要使用sRGB空间,如金属度贴图、粗糙度贴图或者法线贴图等。一旦这些纹理使用sRGB空间可能会造成视觉表现错误。

        纹理过滤模式的选择也是按照需求来。一般来说,我们只需要默认设置的Bilinear Filtering。但是如果你本身觉得像素基本的显示没问题,那Nearest Point Filtering也可以减缓压力。Trilinear Filtering仅有需要开启Mipmap,且对像素清晰度要求比较高时,才需要选择。有时候Bilinear Filtering+ 2x(2倍)的Aniso Level会比Trilinear Filtering + 1x的Aniso Level效果好。大部分资源基本上只要1x的Aniso Level,仅对关键资源使用高于2x的Aniso Level。

        对于美术资源的管控也是我们要重点关注的。如果你使用了纹理图集,那么你应该尽可能将纹理紧密排布,并减少纹理的空白区域。简单来说,你应该控制好图片的大小。除此之外,你还要注意一下纹理图集中各各纹理的生命周期。你应该尽量让同生命周期的纹理在同一个图集中。否则当图集中相当大的一部分资源已经不需要再使用的时候,就会导致部分小资源仍在使用而加载全部纹理图集进而造成的性能浪费。在和美术沟通时,你应该尽量让美术控制一下透明通道的使用,确保图片在尽量小中保证足够的信息量(即不要让美术搞出无意义的图片空白区域)。如果用到序列帧动画,你同样要确保整体序列帧图片的信息密集度,并将序列帧打包成图集。遇到美术出一些颜色相近的贴图,你可以让美术出一张黑白图,然后用材质颜色变化(UI上可以直接设置Image颜色)来实现相同的效果。对于单一的渐变动画,你可以使用曲线来代替,或者将其格式改为单通道纹理。项目中重复的图片资源应该尽量避免,如果有必要可以使用第三方工具帮忙。

纹理设置

        关于纹理设置中的更多的信息,请查阅官方文档:纹理导入设置 (Texture Import Settings) 窗口参考,默认纹理导入设置窗口参考。本文只关心其中部分的设置,并提出优化思路。有些设置信息也在前文有提交,这里也不再说明。

  1. Texture Shape:纹理外形,使用 Texture Shape 属性可选择和定义纹理的形状和结构。有四种形状类型:

    2D:是用于所有纹理的最常用设置;它将图像文件定义为 2D 纹理。这些设置用于将纹理映射到 3D 网格和 GUI 元素以及其他项目元素。

    Cube:将纹理定义为立方体贴图。一般将其用于天空盒或反射探针。此类型仅适用于默认 (Default)、法线贴图 (Normal Map) 和单通道 (Single Channel) 纹理类型。其也可以通过Assets > Create > Legacy > Cubemap生成,也可以通过C#代码Camera.RenderToCubemap在脚本中生成。

    2D Array:将纹理定义为 2D 数组纹理 (2D array texture)。这通常用作某些渲染技术的优化,其中会使用许多具有相同大小和格式的纹理。并且其可以极大提高大量相同大小和格式的纹理访问效率,但需要特定平台支持,可以通过引擎SystemInfo.supports2DArrayTextures接口,在运行时查看是否支持。

    3D:将纹理定义为 3D 纹理 (3D texture)。通过纹理位图方式存储或传递一些3D结构化数据。某些渲染技术使用 3D 纹理表示体积数据。一般用于体积仿真,如雾效、噪声、体积数据、距离场、动画数据等信息,可以外部导入,也可运行时程序化创建。

Texture Shape的选择要依据具体的项目需求来定。

  1. Alpha Source: 指定 Unity 如何从纹理源文件为纹理资源生成 Alpha 值。它有三种选择:

    None :纹理资源不包含 Alpha 通道,无论纹理源文件是否包含 Alpha 通道。

    Input Texture Alpha :如果纹理源文件包含 Alpha 通道,则 Unity 会将纹理源文件的 Alpha 通道应用到纹理资源中。

    From Gray Scale :Unity 通过纹理源文件 RGB 通道的平均值为纹理资源生成 Alpha 通道。

默认选择Input Texture Alpha就好,如果确定不使用原图中的Alpha通道,可以选择None。From Gray Scale我们一般不会选用,除非有具体的需求。

  1. Alpha is Transparency:指示是否扩展颜色通道。当 Alpha 通道用于表示透明度时,此选项有助于避免 Alpha 通道边缘出现滤波伪影。如果不需要图片要半透明可以不开启此选项。这样Alpha信息只需要占1bit。节省内存。

  2. Ignore Png file gamma:启用此选项后,将忽略 PNG 文件中的伽马 (Gamma) 属性。仅当纹理源文件为 PNG 格式时,此选项才可见。这个选项是否启用,取决于当前的png文件中是否因为设置不同gamma属性导致的显示不正常,一般原图制作流程没有特殊设置,这个选项一般默认就好。

  3. Read/Write:此属性用于决定是否可以通过脚本使用Texture2D.SetPixels、Texture2D.GetPixels和其他 Texture2D 类方法访问纹理数据。在内部实现中,Unity 会为脚本访问创建纹理数据的副本,这会使得纹理所需的内存占用加倍。因此,此属性默认为禁用状态,仅在需要通过脚本访问纹理数据时才应启用。

  4. Generate Mipmap:指示是否为该纹理生成 Mipmap。此选项不一定需要开启,具体看情况。Mipmap相关知识点

    • 什么时候不需要生成MipMaps

    在2D场景或者固定视角,摄像机无法缩放远近时,不需要生成MipMaps。这样可以节省纹理的内存占用。

    • 开启Generate Mipmap后,你会发现多了几个选项:

    Mipmap Filtering:其指定 Unity 用于过滤 Mipmap 级别和优化图像质量的方法。有以下几个选项:

     Box:使 Mipmap 级别在尺寸减小时更加平滑。最简单,随尺寸减小,Mipmap纹理变得平滑模糊
    
     Kaiser:在 Mipmap 级别尺寸减小时应用锐化算法。如果纹理在远处显得过于模糊,建议使用此选项。该算法基于 Kaiser Window 类型。

    Preserve Coverage:指定在生成的 Mipmap 中,Alpha 通道是否在透明纹理渲染过程中保留覆盖率。只有需要纹理在开启mipmap后也需要做Alpha Coverage时开启。默认不开启。

    Fadeout to Gray:指示 Mipmap 级别是否应随着 Mipmap 级别的变化逐渐变为灰色。此功能适用于细节贴图。最左侧的滑块表示开始淡出的第一个 Mipmap 级别。最右侧的滑块定义纹理完全变为灰色的 Mipmap 级别。一般不开启,只有在雾效较大时开启不影响视觉效果。

视频中还有说明了一个Border Mip Maps,但是我在Unity上寻找,并没有找到对应的选项。

动画导入设置检查与优化

        动画对应的设置与之前的模型设置也有点关系。如果你对部分说明有些疑惑,你可以看一下前文关于模型设置的部分。

模型设置的Rig选项卡(动画部分)

        模型设置的Rig中有几个关于动画的设置:

Animation Type:指定动画类型。其有以下四种选项:

  1. None:无动画

  2. Legacy:使用旧版动画系统。与 Unity 3.x 及更早版本一样导入和使用动画。

  3. Generic:如果骨架为 non-humanoid(四足动物或任何要动画化的实体),请使用通用动画系统 (Generic Animation System)。Unity 会选择一个根节点,但可以确定另一个用作__根节点 (Root node)__ 的骨骼。

  4. Humanoid:如果骨架为人形(有两条腿、两条手臂和一个头),请使用人形动画系统 (Humanoid Animation System)。Unity 通常会检测骨架并将其正确映射到__ Avatar__。有些情况下,可能需要更改 Avatar 定义 (Avatar Definition) 并手动对映射进行配置 (Configure)。

我们选择原则如下:

  • 无动画选择None

  • 非人形动画选择Generic

  • 人形动画要区分一下情况,人形动画需要Kinematices或Animation Retargeting(动画重定向)功能,或者有自定义骨骼对象时选择Humanoid其他都选择Generic,在骨骼数差不多的情况下,Generic会比Humanoid节省30%甚至更多的CPU的时间。

  • 在移动平台上,如果没什么必要,还是使用Generic,但是要注意本身的骨骼数量也是要控制一下的。

Skin Weights:设置可以影响单个顶点的最大骨骼数量。其有以下两种选项:

  1. Standard (4 Bones):使用最多四个骨骼来产生影响。这是默认值,出于性能考虑,建议使用此设置。

  2. Custom:设置自定义的最大骨骼数量。选择此选项时,将显示最大骨骼/顶点(Max Bones/Vertex)和最大骨骼重量(Max Bone Weight)属性。

    Max Bones/Vertex:定义每个顶点的最大骨骼数(以影响给定顶点)。可为每个顶点设置 1 到 32 个骨骼,但是用来影响顶点的骨骼数量越多,性能成本就越高。

    Max Bone Weight:设置考虑骨骼权重的最低阈值。权重计算将忽略小于此值的任何值,并且 Unity 会将高于此值的骨骼权重放大为总计 1.0。

Unity默认将Skin Weights设定为Standard (4 Bones),但是对于一些不重要的动画对象可以减少到一根。这样可以减少计算量。

Optimize Game Object:在 Avatar 和 Animator 组件中删除和存储所导入角色的游戏对象变换层级视图。如果启用此选项,角色的 SkinnedMeshRenderer 将使用 Unity 动画系统的内部骨架,因此可提高动画角色的性能。但有些情况下会造成角色动画错误,这个选项可以尝试开启但要看表现效果而定。注意如果你的角色是可以换装的,在导入时不要开启此选项,但在换装后在运行时代码中通过调用AnimatorUtility.OptimizeTransformHierarchy接口仍然可以达到此选项效果。

视频中还介绍了一个Optimize Bones,但是我没找到官方对应的文档信息。视频中说是建议开启,其在导入时自动剔除没有蒙皮顶点的骨骼。更多信息可以查阅官方文档。

模型设置的Animation选项卡

        显然模型的Animation选项卡就是动画设置的一部分。对应的设置中,我们要关心以下选项:

Resample Curves:将动画曲线重新采样为四元数值,并为动画中的每个帧生成一个新的四元数关键帧。仅当导入文件包含欧拉曲线时,才显示此选项。默认情况下会启用此选项。禁用此选项可保持动画曲线的原始状态。仅当重新采样的动画与原始动画相比存在插值问题时,才应禁用此选项。

Anim. Compression:导入动画时要使用的压缩类型。其有以下四种选项:

Off:禁用动画压缩。这意味着 Unity 不会在导入时减少关键帧数量。禁用动画压缩可产生最高精度的动画,但性能会降低、文件会更大、运行时内存大小将增加。通常建议不要使用此选项;如果需要更高精度的动画,应启用关键帧减少 (`Keyframe Reduction`) 功能并减小允许的 `Animation Compression Error` 值。

Keyframe Reduction:导入时减少冗余关键帧。如果启用此选项,检视面板将显示 `Animation Compression Errors` 选项。这会影响文件大小(运行时内存)以及如何计算曲线。适用于 `Legacy`、`Generic` 和 `Humanoid Animation Type` 骨架。

Keyframe Reduction and Compression:导入时减少关键帧并在文件中存储动画时压缩关键帧。这仅影响文件大小;运行时内存大小与 `Keyframe Reduction` 相同。如果启用此选项,检视面板将显示 `Animation Compression Errors` 选项。仅适用于 `Legacy Animation Type` 骨架。

Optimal:让 Unity 决定如何进行压缩:通过减少关键帧还是通过使用密集格式。如果启用此选项,检视面板将显示 Animation Compression Errors 选项。仅适用于 `Generic` 和 `Humanoid Animation Type` 骨架。
关于Animation Compression Errors

上文中一直出现的Animation Compression Errors,其实也是其中的一个选项。仅当启用 Keyframe Reduction 或 Optimal 压缩时可用。其有三种错误设置:

  1. Rotation Error:设置旋转曲线压缩的容错度(以度为单位的角度)。Unity 使用此值来确定是否可以删除旋转曲线上的关键点。这表示原始旋转值和消减值之间的最小角度:

  2. Position Error:设置位置曲线压缩的容错度(百分比)。Unity 使用此值来确定是否可以删除位置曲线上的关键点。

  3. Scale Error:设置缩放曲线压缩的容错度(百分比)。Unity 使用此值来确定是否可以删除缩放曲线上的关键点。

Animated Custom Properties:导入您指定为自定义用户属性的任何 FBX 属性。Unity 在导入 FBX 文件时仅支持一小部分属性(例如转换、旋转、缩放和可见性)。一般对应DCC工具中的。您可以借助 extraUserProperties 字段中定义的数据,在导入器脚本中指定标准 FBX 属性(如用户属性)来处理这些属性。在导入期间,Unity 会将所有这些指定属性传递给资源后处理器 (Asset postprocessor),就像“真实”用户属性一样。

动画曲线部分

        点击一个动画资源,我们可以在Inspector视图下看到如下信息:

这些是动画曲线数据信息。你可以在Unity官方文档中找到对应的信息。

Curves (Pos, Rot & Scale):由 Unity 用于动画化游戏对象位置、旋转或缩放的曲线总数。这些曲线用于不属于标准人形骨架的动画游戏对象。在对人形 Avatar 进行动画化时,这些曲线会显示额外非肌肉骨骼(例如尾巴、飘逸的布料或悬垂的吊坠)的计数。如果您有人形动画并发现意外的非肌肉动画曲线,表示动画文件中可能有不必要的动画曲线。

Quaternion:四元数曲线,如上文所述将Resample Curves开启会有。

Euler:欧拉曲线,如果我们将Resample Curves禁用则使用这个曲线。在Unity官方文档中有对应的说明。

Muscles:此 Animator 用于Humanoid动画的肌肉动画曲线数量。这些是用于对标准人形 Avatar 肌肉进行动画化的曲线。除了 Unity 的标准 Avatar 中所有人形骨骼的标准肌肉运动外,此处还包括用于存储根运动位置和旋转动画的两条“肌肉曲线”。

Generic:一般是属性动画曲线,由 Animator 用于动画化其他属性(如材质颜色)的数字(浮点)曲线数量。

PPtr:精灵动画曲线(由 Unity 的 2D 系统使用)的总数。

Curves Count:动画曲线的合计总数。这个数值越大,动画播放起来的性能越差。

Constant:优化为常量(不变)值的动画曲线数量。如果动画文件包含了具有不变值的曲线,Unity 会自动选择此项。在我们动画压缩的时候,Error的数据越大,这个数量越多。其一般不参与采样,所以也算是减少了性能开销(好像不由我们控制)。Inspector窗口中,这个后面的百分比是其占总曲线数的百分比。

Dense:使用“密集”数据(通过线性内插的离散值)存储方法进行优化的动画曲线数量。与“流”方法相比,此方法使用的内存要少得多。

Stream:使用“流”数据(这些值具有用于曲线插值的时间和切线数据)存储方法的动画曲线数量。与“密集”方法相比,此数据占用的内存多得多。

合理优化

        当我们依据项目要求对模型的设置进行修改后,我们还需要对产出的资源进行查看。

  1. 看效果差异(与原始制作动画差异是否明显),只要在肉眼上看不出明显差异,那就没问题。

  2. 看曲线数量。总曲线数量与各种曲线数量越小越好,如果总曲线数量大,则常量曲线比重大更好

  3. 看动画文件大小。以移动平台为例子,动画文件在小几百k或更少合理,超过1M以上的动画文件则考虑是否合理。

资源分析软件AssetCheck

        视频中推荐了一个名为AssetCheck,如果你认为真的是因为资源问题导致的性能卡顿,而你又找不到问题时,或许使用这个工具可以帮你找到问题。

闲言碎语

        总觉得自己就只是在复述视频中的观点罢了,不过我确实为了这文章查找了很多官方文档中的资料,算是自己的文章吧。应该吧ヾ(´・・`。)ノ。