Unity 性能优化 之 静态资源优化 (音频 | 模型 | 纹理 | 动画)

Unity 之 性能优化 -- 静态资源优化

参考性能指标

  • 生成的Apk大小
  • 三角形平均面数/峰值面数
  • 渲染批次
  • SetPassCall
  • Fps
  • 内存开销
  • 纹理资源开销
  • Mesh资源开销
  • 音效资源开销

场景中的摄像机数量会影响整个渲染流程的复杂度

场景中的灯光数量会影响整个场景的光照复杂度与阴影复杂度


静态资源

资源工作流程

导入 -- 创建 -- 构建 -- 分发 -- 加载

资源分类

  • 外部导入资源:模型网格Mesh、纹理、音乐音效、字体、动画、视频等。
  • 内部创建资源:Prefab、AnimationController、Timeline、RenderTexture、ParicleSystem、VFX等。

原理小结

我们创建的资源在不同平台可能涉及到导入设置的改变,或者你创建的资源在不同开发平台机器上打开,或者使用了其他第三方开发包。这些都需要涉及到平台导入。

不同平台上的合理的资源导入设置与资源规格,可以给程序带来较高的效率。

推荐使用资源检测工具:Unity UPR -- Asset Chechker


Audio 实战优化建议

资源检查报告------Audio部分问题解读

  • 根据平台选择合理的音频设置,原始音频资源尽量采用未压缩WAV格式
  • 移动平台对音乐音效统一采用单通道设置(Force to Mono),并将音乐采样频率设置为22050Hz
  • 移动平台大多数声音尽量采用Vorbis压缩设置,IOS平台或不打算循环的声音可以选择MP3格式,对于简短、常用的音效,可以采用解码速度快的ADPCM格式(PCM为未压缩格式)
  • 当实现静音功能时,不要简单的将音量设置为0,应销毁音频(AudioSource)组件,将音频从内存中卸载。

音频片段加载类型说明

  • 简短音效导入后小于200kb,采用Decompress on Load模式
  • 对于复杂音效,大小大于200kb,长度超过5秒的音效采用Compressed In Memory模式
  • 对于长度较长的音效或背景音乐则采用Streaming模式,虽然会有CPU额外开销,但节省内存并且加载不卡顿


模型导入工作流程

DCC中模型导出

Unity 支持多种标准和专有模型文件格式(DCC)。Unity 内部使用 .fbx 文件格式作为其导入链。最佳做法尽可能使用 .fbx 文件格式,并且不应在生产中使用专有文件格式。

优化原始导入模型文件,删除不需要的数据

  • 统一单位
  • 导出的网格必须是多边形拓扑网格,不能是贝塞尔曲线、样条曲线、NURBS、NURMS、细分曲面等
  • 烘培Deformers,在导出之前,确保变形体被烘培到网格模型上,如骨骼形变烘培到蒙皮权重上
  • 不建议模型使用到的纹理随模型导出
  • 如果你需要导入blend shape normals,必须要指定光滑组smooth groups
  • DCC导出面板设置, 不建议携带场景信息导出,如不建议导出摄像机、灯光、材质等信息,因为这些的信息与Unity内默认都不同。除非你自己为某DCC做过自定义导出插件。

.DCC中Mesh生产规范

必须

  • 统一单位;
    网格必须是多边形拓扑网格,而不能是贝塞尔曲线、样条曲线、NURBS、细分曲面等;

建议

  • 尽可能合并网格、最小化面数、不要使用微三角形、分布均匀;
  • 尽可能使用共享材质、减少材质个数;
  • 尽可能不使用蒙皮网格;
  • 尽可能少的骨骼数量,导入Unity前删除IK节点;
  • 尽可能减少影响SkinWeights的骨骼数量;

美术关心的导出设置

原始模型文件对性能的影响点:

  • 最小化面数,不要使用微三角形,分布尽量均匀
  • 合理的网络拓扑和平滑组
  • 尽量少的使用材质个数
  • 尽可能少的使用蒙皮网格
  • 尽可能少的骨骼数量
  • FK与IK节点没分离,IK节点没删除

模型导出检查流程

  1. 检查下是否存在Transform中Scale不为(1,1,1)的情况。若存在:如果好修改就顺手改掉;不好改则建议让美术同学重新加工下。Transform中Scale为(1,1,1)是后续检查流程的前提。
  2. 确保Transform中Scale为1时,再次查看模型导入配置中的ScaleFactor和ConvertUnits的配置分别为1和enable。
  3. 若上述均已确认但大小依然不对,则可以认为是【Unity对于该模型格式(Fbx等)的尺度预设】与【美术对于该模型格式的默认尺度设置】不一致。
    • 处理方案一:由美术重新调整模型尺度,即确保导出fbx中的单位1对应的是厘米。
    • 处理方案二:调整Unity模型导入配置中的ScaleFactor。
  4. 不管怎么样,都不应该让Transform的Scale不为(1,1,1)。
    BuildSetting-PlayerSetting-Optimization存在模型优化选项
    VertexCompression配置项:
    • 对顶点使用Half的精度格式存储。
    • 其将减少内存中网格数据的大小,并稍微减少包体文件大小,同时提高 GPU 性能。
    • 其将影响项目中每个Mesh的设置。对同一Mesh数据,顶点压缩与网格压缩不会同时存在,若FBX的ImportSetting中启动MeshCompression相关配置,则此处的VertexCompression将失效。
    • 该配置中各个选项具体是指,对哪些channel使用顶点压缩,默认为Normal、Tangent、TexCoord0、TexCoord2、TexCoord3。默认开启压缩的通道为Unity推荐配置,若压缩更多通道,需确认是否会产生额外的伪影。
    • OptimizeMeshData选项:
      开启该选项时,则在打包时剔除Mesh顶点未被使用的channel数据。

模型优化建议

  • 尽可能的将网格合并到一起
  • 尽可能使用共享材质
  • 不要使用网格碰撞体
  • 不必要不要开启网格读写
  • 使用合理的LOD级别
  • Skin Weights受骨骼影响个过多
  • 合理压缩网格
  • 不需要rigs和BlendShapes尽量关闭
  • 如果可能,禁用法线或切线

资源检查报告------FBX部分问题解读

其中两项建议与模型动画有关,而测试项目中所有模型资源都不涉及动画,可以将Rig标签下的Animation Type设置为None,并关闭Animation标签下的Import Animations选项,设置Materials标签中的Material Creation Mode为None.

开启Project Settings ---> Player ---> Optimization下的Vertex Compression与Optimize Mesh Data选项



纹理优化

纹理基础概念

纹理一般是指应用于模型表面用来增加细节的位图图像,通常情况下3D对象上一般需要一张或多张纹理,纹理需要通过材质着色器映射才能到3D对象面。

一般Unity中的纹理资源来自于外部图像编辑工具,并导入到Unity中使用。当然也有一部分可以通过程序化生成纹理,包括在编辑器下通过代码或烘焙生成,也可以运行时动态生成

纹理类型

  • Default: 默认的纹理类型格式
  • Normal map: 法线贴图,可将颜色通道转换为适合实时法线贴图格式
  • Editor GUI and Legacy GUI: 在编辑器GUI控件上使用纹理请选择此类型
  • Sprite(2D and UI): 在2D游戏中使用的精灵(Sprite)或UGUI使用的纹理请选择此类型
  • Cursor: 鼠标光标自定义纹理类型
  • Cookie: 用于光照Cookie剪影类型的纹理
  • Lightmap: 光照贴图类型的纹理,编码格式取决于不同的平台
  • Single Channel: 如果原始图片文件只有一个通道,请选择此类型

纹理大小

选择合适纹理大小应尽量遵循以下经验:

  • 不同平台、不同硬件配置选择不同的纹理大小,Unity下可以采用bundle变体设置多套资源、通过Mipmap限制不同平台加载不同level层级的贴图。
  • 根据纹理用途的不同选择不同的纹理加载方式,如流式纹理加载Texture Streaming、稀疏纹理Sparse Texture、虚拟纹理VirtualTexture等方式。
  • 不能让美术人员通过增加纹理大小的方式增加细节,可以选择细节贴图DetailMap或增加高反差保留的方式。
  • 在不降低视觉效果的情况下尽量减小贴图大小,最好的方式是纹理映射的每一个纹素的大小正好符合屏幕上显示像素的大小。如果纹理小了会造成欠采样,纹理显示模糊,如果纹理大了会造成过采样,纹理显示噪点。可以充分利用Unity编辑器中的【BuildIn:SceneView->DrawMode->Mipmap】或【URP:URP Render Debugger】,来查看在游戏摄像机视角下进行overdraw检查,进而确认所需纹理大小。

纹理颜色空间

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

纹理压缩

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

​ 如下图为未压缩、ETC2、ASTC6x6三种格式文件大小对比,我们可以看到在质量相差不大的情况下ASTC6x6压缩下大小可以减少到接近未压缩的十分之一。

纹理图集

纹理图集是一系列小纹理图像的集合,

  • 优点:

    • 一是采用共同纹理图集的多个静态网格资源可以进行静态合批处理,减少DrawCall调用次数。
    • 二是纹理图集可以减少碎纹理过多,因为他们打包在一个图集里,通过压缩可以更有效的利用压缩,降低纹理的内存成本和冗余数据。
  • 缺点:

    • 美术需要合理规划模型,并且要求模型有相同的材质着色器,或需要制作通道图去区分不同材质。制作和修改成本较高。
    • 纹理尺寸限制。合并到纹理图集中的每个小纹理都必须符合一定的尺寸限制。如果某些小纹理尺寸过大,可能会导致整个图集的尺寸超出硬件或软件的限制,从而限制了使用纹理图集的场景。
    • UV空间限制。在将多个小纹理合并成一个大纹理时,需要为每个小纹理分配一定的UV空间。如果小纹理之间的UV空间重叠或浪费过多,可能会导致图集的利用率下降,从而减少了优化效果。
    • 动态更新困难。由于纹理图集是静态的,一旦创建后就不易修改。这意味着如果需要动态加载或更新纹理,可能需要重新生成整个图集,这会带来一定的开销和复杂性。
    • 纹理压缩损失。将多个小纹理合并成一个大纹理后,通常需要对图集进行压缩以减少内存占用。然而,压缩会引入一定程度的纹理损失,可能会导致图像质量下降。
    • 不适用于所有场景。虽然纹理图集在许多场景下都能够有效提高性能,但并不适用于所有情况。例如,在需要频繁动态加载或更新纹理的场景下,纹理图集可能并不适用,因为它们不太灵活。

纹理过滤

  • Nearest Point Filtering: 临近点采样过滤最简单、计算量最小的纹理过滤形式,但在近距离观察时,纹理会呈现块状。
  • Bilinear Filtering: 双线性采样过滤会对临近纹素采样并插值化处理,对纹理像素进行着色。双线性过滤会让像素看上去平滑渐变,但近距离观察时,纹理会变得模糊。
  • Trilinear Filtering: 三线性过滤除与双线性过滤相同部分外,还增加了Mipmap等级之间的采样差值混合,用来平滑过度消除Mipmap之间的明显变化。
  • Anisotropic Filtering: 各向异性过滤可以改善纹理在倾斜角度下的视觉效果,跟适合用于地表纹理。

纹理Mipmap

Mipmap纹理

逐级减低分辨率来保存纹理副本。相当于生成了纹理LOD,渲染纹理时,将根据像素在屏幕中占据的纹理空间大小选择合适的Mipmap级别进行采样。

优点:

  • GPU不需要在远距离上对对象进行全分辨率纹理采样,因此可以提高纹理采样性能。
  • 同时也解决了远距离下的过采样导致的噪点问题,提高的纹理渲染质量。

缺点:

  • 由于Mipmap纹理要生成低分辨率副本,会造成额外的内存开销。

可以通过Unity提供的MipMap Streaming功能,在运行时限制之采样某个级别以下的纹理进行不同设备上的适配。另外MipPap也是做Hierarchy Z Code的前提条件,它是目前比较流行的剔除方案,

其他设置

Texture Shape

  • 2D 最常用的2D纹理,默认选项
  • Cube 一般用于天空和与反射探针,默认支持Default、Normal、Single Channel几种类型纹理,可以通过Assets > Create > Legacy > Cubemap生成,也可以通过C#代码 Camera.RenderToCubemap在脚本中生成
  • 2D Array 2D纹理数组,可以极大提高大量相同大小和格式的纹理访问效率,但需要特定平台支持,可以通过引擎SystemInfo.supports2DArrayTextures 接口运行时查看是否支持。
  • 3D 通过纹理位图方式存储或传递一些3D结构话数据,一般用于体积仿真,如雾效、噪声、体积数据、距离场、动画数据等信息,可以外部导入,也可运行时程序化创建。

Alpha Source

  • 默认选择Input Texture Alpha就好,如果确定不使用原图中的Alpha通道,可以选择None。另外From Gray Scale我们一般不会选用

Alpha Is Transparency

  • 指定Alpha通道是否开启半透明,如果位图像素不关心是否要半透明可以不开启此选项。这样Alpha信息只需要占1bit。节省内存

Ignore Png file gamma

  • 是否忽略png文件中的gamma属性,这个选项是否忽略取决于png文件中设置不同gamma属性导致的显示不正常,一般原图制作流程没有特殊设置,这个选项一般默认就好。

Read/Write

  • 开启此选项会导致内存量增加一倍,默认我们都是不开启,除非你的脚本逻辑中需要动态读写该纹理时需要打开此选项。

Streaming Mipmaps(Texture Streaming部分讲解)

Virtual Texture Only(虚拟部分讲解)

什么时候不需要生成MipMaps?

Generate Mip Maps

  1. 2D场景
  2. 固定视角,摄像机无法缩放远近
  • Border Mip Maps 默认不开启,只有当纹理的是Light Cookies类型时,开启此选项来避免colors bleeding现象导致颜色渗透到较低级别的Mip Level纹理边缘上
  • MipMap Filtering
    • Box 最简单,随尺寸减小,Mipmap纹理变得平滑模糊
    • Kaiser,避免平滑模糊的锐化过滤算法。
  • Mip Maps Preserve Coverage,只有需要纹理在开启mipmap后也需要做Alpha Coverage时开启。默认不开启。
  • Fadeout MipMaps, 纹理Mipmap随Mip层级淡化为灰色,一般不开启,只有在雾效较大时开启不影响视觉效果。

纹理相关优化建议

选择合适纹理过滤的最佳经验:

  • 使用双线性过滤平衡性能和视觉质量。
  • 有选择地使用三线性过滤,因为与双线性过滤相比,它需要更多的内存带宽。
  • 使用双线性和 2x 各向异性过滤,而不是三线性和 1x 各向异性过滤,因为这样做不仅视觉效果更好,而且性能也更高。
  • 保持较低的各向异性级别。仅对关键游戏资源使用高于 2 的级别。

其他可能有问题的纹理类型

  • 纹理图集大小设置不合理,图集利用率低。【应合理设置图集大小】
  • 同一图集中纹理资源生命周期不一致,也会造成内存长时间难以释放。【应尽可能的将类似生命周期的小纹理打到同一图集中】
  • 不合理的半透明UI,占据大量屏幕区域,造成Overdraw开销。【应尽量从UI设计上进行避免】
  • 大量2D序列帧动画,而且图片大,还不打图集。
  • 大量只有颜色差异的图片。【可采用分离变化区域贴图,同时使用UI的九宫格缩放】
  • UI背景贴图而不采用9宫格缩放的图。
  • 纯色图没有使用Single Channel。
  • 不合理的通道图利用方案。
  • 大量渐变色贴图,没有采用1像素过渡图,也不采用Single Channel, 粒子特效中较为常见。【贴图可以替换为曲线数据或采用单像素梯度纹理,以减少贴图的内存开销和加载开销】

动画优化

Rig标签页

Animation Type

  • None 无动画
  • Legacy 旧版动画,不要用
  • Generic 通用骨骼框架
  • Humanoid 人形骨骼框架

选择原则:

  • 无动画选择None
  • 非人形动画选择Generic
  • 人形动画
    • 人形动画需要Kinematices或Animation Retargeting功能,或者没有有自定义骨骼对象时选择Humanoid Rig
    • 其他都选择Generic Rig,在骨骼数差不多的情况下,Generic Rig会比Humanoid Rig省30%甚至更多的CPU的时间。

Skin Weights

​ 默认4根骨头,但对于一些不重要的动画对象可以减少到1根,节省计算量

Optimize Bones

​ 建议开启,在导入时自动剔除没有蒙皮顶点的骨骼

Optimize Game Objects

​ 在Avatar和Animatior组件中删除导入游戏角色对象的变换层级结构,而使用Unity动画内部结构骨骼,消减骨骼transform带来的性能开销。可以提高角色动画性能, 但有些情况下会造成角色动画错误,这个选项可以尝试开启但要看表现效果而定。注意如果你的角色是可以换装的,在导入时不要开启此选项,但在换装后在运行时在代码中通过调用AnimatorUtility.OptimizeTransformHierarchy接口仍然可以达到此选项效果。

Animation标签页

Resmple Curves

​ 将动画曲线重新采样为四元数数值,并为动画每帧生成一个新的四元数关键帧,仅当导入动画文件包含尤拉曲线时才会显示此选项

Anim.Compression

  • Off 不压缩,质量最高,内存消耗最大
  • Keyframe Reduction 减少冗余关键帧,减小动画文件大小和内存大小。
  • Keyframe Reduction and Compression 减小关键帧的同时对关键帧存储数据进行压缩,只影响文件大小。
  • Optimal,仅适用于Generic与Humanoide动画类型,Unity决定如何进行压缩。

Animation Custom Properties

​ 导入用户自定义属性,一般对应DCC 工具中的extraUserProperties字段中定义的数据

动画曲线数据信息

  • Curves Pos: 位置曲线
  • Quaternion: 四元数曲线 Resample Curves开启会有
  • Euler: 尤拉曲线
  • Scale: 缩放曲线
  • Muscles: 肌肉曲线,Humanoid类型下会有
  • Generic: 一般属性动画曲线,如颜色,材质等
  • **PPtr:**精灵动画曲线,一般2D系统下会有
  • **Curves Total: **曲线总数
  • Constant: 优化为常数的曲线
  • Dense: 使用了密集数据(线性插值后的离散值)存储
  • Stream: 使用了流式数据(插值的时间和切线数据)存储

动画文件导入设置优化后信息查看原则

  1. 一看效果差异(与原始制作动画差异是否明显)
  2. 二看曲线数量(总曲线数量与各种曲线数显,常量曲线比重大更好)
  3. 三看动画文件大小(以移动平台为例,动画文件在小几百k或更少为合理,查过1M以上的动画文件考虑是否进行了合理优化)

本文整理自:Metaverse大衍神君《Unity性能优化》

相关推荐
我叫汪枫2 小时前
深入探索React渲染原理与性能优化策略
前端·react.js·性能优化
卓码软件测评5 小时前
第三方软件测试机构【性能测试工具用LoadRunner还是JMeter?】
java·功能测试·测试工具·jmeter·性能优化
Thomas_YXQ12 小时前
Unity3D RectTransform.rect属性详解
unity·编辑器·游戏引擎·材质
平行云12 小时前
赋能数字孪生:Paraverse平行云实时云渲染平台LarkXR,提供强大的API与SDK用于二次开发和深度集成
3d·unity·ue5·webgl·实时云渲染·云xr
SmalBox13 小时前
【光照】[光照模型]发展里程碑时间线
unity·渲染
0wioiw013 小时前
Unity(①基础)
unity·游戏引擎
死也不注释14 小时前
【Unity UGUI 交互组件——InputFild(TMP版本)(11)】
unity·游戏引擎·交互
猫林老师21 小时前
LazyForEach性能优化:解决长列表卡顿问题
性能优化
卓码软件测评21 小时前
第三方软件测评机构:MongoDB分片集群写入吞吐量与延迟第三方性能测评
数据库·mongodb·性能优化·压力测试