目录
前言
unity性能优化之内存的优化
一、unity Analysis工具的使用。
二、内存优化方法
1、设置和压缩图片
2、图片格式
3、动画文件
4、模型
5、RenderTexture(RT)
6、分辨率
7、资源的重复利用
8、shader优化
9、对bundle进行良好的管理
10、巧用静态合批
11、关注代码对象所占内存
·12、音频
13、字体裁剪
总结:
在unity项目实际开发中,总是逃不开对于项目进行优化,内存、GC,渲染效率(GPU、drawcall)、发烫耗电等问题往往是对技术的最基本的技术考验,同时又有实际程序员的个体差异,结果往往各不相同。
作为技术通常从技术角度考虑问题,将一个好好的游戏优化成一个白模游戏,会说:“你看,我在技术上是达标,是你的资源太复杂了”;作为有责任心的制作人或者美术负责人就会说:“我做的东西效果好的很,到游戏里怎么成这个样子了。”技术会要求美术资源问题,要么重做,要么大面积修改。作为有骨气的美术通常带着怨气不予理睬,这样的结果可想而知,项目就无法做下去。
该篇我不仅仅从技术的角度来讲解unity 项目如何优化,同时也从其他方面作出阐述。因为我们最终的目的是将项目做成大家都想要的效果,而不是理想的认为做出仅仅是我想要的东西。
由于篇幅原因,本文仅从内存方面如何优化。
不管硬件如何发展,内存永远满足不了程序员对更大内存的渴望,也无法杜绝个别不靠谱的程序员所写出来的泄露的Bug,所以控制我们程序所用得内存至关重要。在此讲解方法之前,需要了解unity Analysis工具的使用。
不同的unity版本可能有个体差异,但是基本相同,我就以2021.3.2f1版本为例:
找到菜单栏中window->Analysis->Profiler
点击并进入分析器 ->获取内存快照 take sample
这样我们就可以看到textere2D列表下图片所占用的内存(memory)以及被图片被引用的次数(refcount)。再详细的如何使用就不再做赘述了。
在unity项目中,控制内存的方法大致有如下方法:
如果一张图片格式是RGBA,1024*1024大小的图片是4M,如果改成512*512那么就是1M,可以看出图片的大小对于内存的影响是多大。
在unity项目中,我们通常设定的规则是尽可能不要设置操作1024*1024大小,对于通用的图片(如共用的界面图集、光照贴图,模型贴图等)。图片大小原则是就小不就大,能使用小图的尽可能使用小尺寸图片。一般来讲移动端的最大尺寸最高限定在2048*2048,除个别UI图集,其他的应该都要在1024*1024以下。
图片过大尺寸会造成以下问题:
1)加载单张图片需要的是连续大小的内存,因无法找到足够大小的连续内存而造成闪退或程序异常问题
2)部分机型不支持该尺寸而造成异常
在unity中我们可以根据不同平台选择图片大小
在图片inspector面板中,我们看到图片在该平台下实际大小为4096*4096,这远远超过我们设定的标准,应该叫美术小伙伴进行修改。
我们还可以对图片尺寸做最大的限制,当然最好不要这么做,因为这不是常规操作。
同样,决定纹理所占内存大小的还有格式,我们应该根据实际情况选择我们想要的格式
对于不同平台我们应该选定不同的格式:
android应该尽可能选择ETC(不带透明通道的)或ECT2(带透明通道的)
IOS平台应该选择astc或pvrtc格式,根据质量需要选定具体压缩比率。当然对于ASTC格式安卓和IOS都是支持的,具体压缩格式就不在该文章中表述了。
pc根据实际需要选择能选择DXT格式或BC7格式。
格式相关详细信息,参考各平台的推荐、默认和支持的纹理压缩格式 - Unity 手册 (unity3d.com)
在Texture Inspector面板中有一个minmap 选项
mipmap勾选,会让我们多出1/3左右的内存,但是mipmap有时也有及其的好处
减少摩尔纹和闪烁,同时可以减少GPU的带宽需求。所以要根据实际情况而定。
1)减少动画文件浮点数的精度
动画.anim)文件往往也是内存的重灾区,我们用文本编辑器软件打开发现,它的格式如下;
内容中有大量的精度9位的数据,在一般情况损失一定的精度对动作的影响并不大,实际项目中我一般选定保留三位或4位精度。
注意:降低精度有可能造成模型的个别动作不连贯,需要排查。
2)减少不必要的动画帧数
在不影响效果的情况,需要美术配合减少动画的帧数。实际项目中,我们设定帧数在30
帧。
1)减少面数
一个高精度模型有时有几万三角面,可能就有几M,通过美术减面的方式,这是最直接,但是以有时候因为减面引起美术效果不达标问题,或者锯齿严重,这时应该需要技术或者技术美术提高技术工艺等手段。
做过二次元的小伙伴就知道,锯齿是美感的杀手。近几年比较流行的本村线的分UV的方法,能在面数相对少的情况下锯齿效果改善很多。
2)模型insepctor选项中read/write选项
对于模型而言,Unity对于这个选项默认开启。
当项目会在运行过程中通过代码修改Mesh,或者Mesh被用来作为MeshCollider组件的基础时,Unity要求这个属性必须开启。如果模型没有用到MeshCollider中或者不需要通过代码修改,将这个属性改成false可以节省一半的内存资源。
2)模型insepctor面板中mesh Compression
mesh Compression 是对unity自动对模型压缩的选项,可以根据实际情况而定选择Low,medium,high等压缩质量。模型约low,顶点数就少,那么占用内存自然就越少。
对于RT文件的使用,我们可能不可避免。但是RT文件的特殊属性,通常是RGBA类型,所以在使用的时候我们应该坚持够用就行,尽可能满足需求的同时少用。考虑缓存的方式,不要频繁创建,以免需要申请连续内存失败造成程序奔溃问题。
根据实际情况和渲染效果设置分辨率,调用 Screen.SetResolution(newWidth, height, true);接口,可以按照、低-中-高等配置设置。分辨率的设置,影响的不仅仅是内存,同时对于渲染也有很多大的影响。
在场景中,如MMORPG或者街道场景,对3D 模型的重复利用也能减少内存。
1)standard shader
默认的unity standard PBR Shader由于其变体非常多,当打包编译的时候,Shader文件文件实体非常大,大概近100M的内存空间。应该不要使用unity standdard shader或者默认的粒子shader。有时候可能发现自己并没有使用standard Shader,什么通过UWA或连接手机在unity编辑器的分析列表中还是存在引用呢?
这是因为如果倒入模型时没有指定shader,那么系统会自动给一个默认的standard材质,所以在导入模型的时候,要查看材质列表是否为空,如图:
我们可以Editor模式下的代码钩子,定义一个类继承AssetPostprocessor类来做监听模型导入时的ModelImporter设置材质信息。
好的bundle的管理应该不仅仅是管理Bundle本身的加载和卸载,同时也要考虑资源的命中率,考虑在何时真正卸载该资源或永久缓存该资源。
缓存是个好东西,有的程序为了游戏流畅,将很多资源预先加载到内存中,请切记,考虑流畅的同时也要考虑内存使用情况。
同时,对于bundle的分割也很关键,它的颗粒是多大,怎么分就很关键了。
如我们的游戏有主城和战斗场景,主城是不参与战斗的,只有闲人、人物NPC、剧情表演等,那么在主城就不需要加载角色的技能动作
如果是mmorpg,角色会频繁进入我们的视野,我们可以把技能动作和基础的跑动等动作分开在不同的bundle中,而不是打在一个bundle中。因为战斗动作可能并不需要,因为在你的视野后,对方一会就传送到其他地图了。
静态合批(将场景的物件设置为static)减少Drawcall 有比较好的效果,相对也比较简单。实际发现静态合批的实际会生成一个个合并的模型,所以在实际运用中,有两份模型内存
那么我们如何选择静态合批呢?
我们应该遵循这样的一个原则,如果该物件重复物件比较多、不需要移动的,并且比较小的物件,如:城市的垃圾桶模型,路灯等模型,我们可以选择静态。不重复的、面数多的就不需要将它设定为static 物件。
UWA和腾讯的wetest等unity性能分析软件可以分析哪些代码对象占用内存比较多,我们可以根据分析的结果做判断,并一一排查。
对于音频文件,一个2M的文件可能在内存中解压后占用内存20M
1)建议启用Force to Mono(强制改成单声道)
为什么建议通过勾选Force To Mono来优化音频呢?
被建议的音频是双声道音频,且左右两声道的音乐完全相同,可以用勾选ForceToMono的方式强制将此音频修改为单声道,内容不丢失的情况下可以减少它的使用内存和大小。特别是在移动平台下几乎听不出任何区别。如果左右声道内容不同,开启ForceToMono会导致听到的声音错误。
2)选择正确的压缩格式(Compression format)
一般情况下,应该尽可能使用未压缩的wav文件作为音频源文件,通过不同平台支持的压缩格式控制压缩比。一般移动平台下,unity下大多数音频文件采用Vorbis压缩方法。如果音乐不循环可以使用MP3格式。一些操作系统对特定的压缩格式有额外的优化,比如在iOS系统上可以使用MP3格式。此外一些简短常用的音效可以使用ADPCM格式。虽然这种格式的压缩比可能不是最好的,但在播放过程中解码速度很快。总之,音频压缩策略需要考虑不同压缩格式在不同平台下的特点,以及音乐音效文件在不同用途下使用不同的压缩格式。
3) 重新 采样率( override Sample Rate)
根据实际需要选择采样的率,来降低内存。
Unity使用的都是默认的Arial动态字体,这字体是微软系统自带的一个字体库,它的大小可能十几MB左右,在一般情况下是可以忽略它的大小,但是如果是手机游戏,微信小游戏这一类对安装包有极大要求的游戏,就需要减少安装包的大小,而字体就好比一个仓库,默认情况下他会把所有的文字都包含在库里,可实际上游戏开发时,大部分的文字我们并没有用到,但是Unity会把这些字体跟着安装包一块打包导出,这无形增加了安装包的大小,为此我们需要对字体进行优化也就是“裁剪”“。
字体的裁剪可以通过FontSubsetGUI,、FontCreator这两个软件,具体怎么使用大家到网上搜索即可,这里只抛砖引玉。
降低内存的同时,我们有时候会带来其它负面印象。比如:选择音频的压缩格式时,有可能我们带来失真效果;过多的静态合批Static场景物件会造成内存过多,不静态合批static场景物件,有可能渲染压力比较大,drawcall过多。
所以在实际运用中,优化方法是固定的,但是也要根据实际情况取其利弊关系。不能一概而论。由于编辑器和真机环境下有时会有截然不同的结果,要借用一些测试工具,UWA和wetest就非常好用,具体就不作赘述。
下一章:unity性能优化之drawcall优化-1