unity优化冷启动时间/加载时间总结
本文一部分博主并未實(shí)踐過(guò),只是做一個(gè)總結(jié),如有錯(cuò)誤,請(qǐng)指正
目錄
一.概念了解
二.優(yōu)化目的
1.保證游戲流暢度的基礎(chǔ)上DrawCall越小越好
2.Statistics統(tǒng)計(jì)面板參數(shù)
3.打包編譯
三.優(yōu)化方法
1.編譯配置方面優(yōu)化
①.使用IL2CPP進(jìn)行打包
②.強(qiáng)烈建議使用IL2CPP后端,如果使用IL2CPP,則可以忽略第6條。
③.攝像機(jī)的clipping planes用到足夠就好,越小回越少drawcall
④.檢查場(chǎng)景中的光源
?
2.代碼優(yōu)化
①.Tolua綁定和Lua資源加載。
②.代碼文件可以編譯成.dll文件
③.注意設(shè)置Web請(qǐng)求的超時(shí)時(shí)長(zhǎng)
④.一些compoment的update可以等loading結(jié)束后才執(zhí)行,減少加載時(shí)每幀的開(kāi)銷(xiāo)
⑤.Transform不能放在for循環(huán),getcompoment也是。
⑥.setactive改造為設(shè)置進(jìn)來(lái)時(shí)判斷是否與之前的值一樣。因?yàn)楸旧韘etactive每次真是調(diào)用都回有g(shù)c
⑦.string不能直接加
⑧.parent用setparent替換。
⑨.協(xié)程用得多,這塊盡量用update或lateupdate替換,因?yàn)閰f(xié)程本身在unity會(huì)創(chuàng)建實(shí)體來(lái)管理,會(huì)產(chǎn)生少量得gc
⑩.減少new waitforsecond的使用并且把他存在一個(gè)變量中
?.特效的order的問(wèn)題,同一個(gè)材質(zhì)的應(yīng)該放在同一個(gè)order下,不同的材質(zhì)一定要放在不同的order下。
?.去掉了加載模型后的卸載行為
?.Aup另一個(gè)線程去做gpu數(shù)據(jù)
?.減少不必要使用的插件
?.一些重復(fù)加載的資源,可以保存下來(lái)
?.字典的key不能用枚舉
3.資源優(yōu)化
①.盡量少的使用Resources方式管理資源,建議使用AssetBundle的方式管理
②.紋理資源選擇合適的壓縮格式進(jìn)行壓縮
③.模型優(yōu)化
(1).網(wǎng)格資源
(2).LOD層級(jí)細(xì)節(jié)技術(shù)
(3).OcclusionCulling遮擋剔除技術(shù)
(4).Lightmapping光照貼圖技術(shù)
(5).Mesh合并
(6) 去掉多余的mesh
(8).骨骼動(dòng)畫(huà)開(kāi)啟optimizeGameObjects選項(xiàng),減少骨骼運(yùn)算。
(9).關(guān)閉?Read/Write Enabled?設(shè)置?
(10).使用Mesh壓縮?
④.音樂(lè)加載優(yōu)化
⑤.資源重復(fù)利用
?⑥.Shader編譯時(shí)間過(guò)長(zhǎng)。
⑦.調(diào)整層級(jí),把相同的altas放在一個(gè)順序的層級(jí)里
⑦.資源審查
⑧.資源后處理
4.UI優(yōu)化
①.有一些ui上掛了剛體,但其實(shí)ui是沒(méi)必要用剛體的,增加額外的組件會(huì)增加額外的開(kāi)銷(xiāo)。(ngui會(huì)加上rigidbody)
②.移除ui圖片的read/write,mipmap
5.設(shè)計(jì)優(yōu)化
①.啟動(dòng)場(chǎng)景不放模型,只放UI
②.項(xiàng)目中添加一個(gè)Loading場(chǎng)景,這個(gè)場(chǎng)景會(huì)是游戲啟動(dòng)的第一個(gè)場(chǎng)景。
6.內(nèi)存優(yōu)化
①.設(shè)定了若干包圍盒,勾畫(huà)出一塊塊小區(qū)域。一旦玩家離開(kāi)包圍盒太遠(yuǎn),程序就把包圍盒里面的物件卸載出內(nèi)存。包圍盒略微擴(kuò)大,允許包圍盒重疊,并可以用多個(gè)包圍盒來(lái)定義一個(gè)區(qū)域。同一個(gè)場(chǎng)景物件只可以屬于一個(gè)區(qū)域,即使它的位置在多個(gè)區(qū)域內(nèi)。(區(qū)域可以重疊)
②.放置Mono內(nèi)存泄漏
參考:
?一.概念了解
?app冷啟動(dòng): 當(dāng)應(yīng)用啟動(dòng)時(shí),后臺(tái)沒(méi)有該應(yīng)用的進(jìn)程,這時(shí)系統(tǒng)會(huì)重新創(chuàng)建一個(gè)新的進(jìn)程分配給該應(yīng)用, 這個(gè)啟動(dòng)方式就叫做冷啟動(dòng)(后臺(tái)不存在該應(yīng)用進(jìn)程)。
?app熱啟動(dòng): 當(dāng)應(yīng)用已經(jīng)被打開(kāi), 但是被按下返回鍵、Home鍵等按鍵時(shí)回到桌面或者是其他程序的時(shí)候,再重新打開(kāi)該app時(shí), 這個(gè)方式叫做熱啟動(dòng)(后臺(tái)已經(jīng)存在該應(yīng)用進(jìn)程)。
二.優(yōu)化目的
1.保證游戲流暢度的基礎(chǔ)上DrawCall越小越好
DrawCall即為由CPU下達(dá)命令,調(diào)用OpenGL或DirectX接口進(jìn)行解析并由GPU進(jìn)行渲染顯示的過(guò)程稱(chēng)為一次DrawCall。
在Unity中查看DrawCall參數(shù),Window / Profiler 或者Ctrl+7 快捷鍵打開(kāi) Profiler性能分析器面板。
2.Statistics統(tǒng)計(jì)面板參數(shù)
? ? ? ? FPS(幀數(shù)):越大越好
CPU(處理器計(jì)算速度):越低越好
render thread(渲染線程,GPU渲染所需要的時(shí)間):越低越好
Batches(渲染批次):與DrawCall關(guān)聯(lián),是Unity自動(dòng)分類(lèi)的渲染批次
Tris(三角面數(shù)):相機(jī)視野范圍內(nèi)的三角面數(shù)量
Verts(頂點(diǎn)數(shù)):相機(jī)視野范圍內(nèi)的頂點(diǎn)數(shù)量
SetPass calls:Unity中的Shader中包含很多Pass塊,每當(dāng)GPU即將去運(yùn)行一個(gè)Pass塊之前,就會(huì)產(chǎn)生一個(gè)“SetPass call”,在描述性能開(kāi)銷(xiāo)上更有說(shuō)服力
3.打包編譯
- 放到Plugins目錄下的貼圖不會(huì)打包進(jìn)去
- 放到Plugins目錄下的dll會(huì)自動(dòng)打包,代碼也會(huì)打包
- 放在Resources目錄下的資源會(huì)自動(dòng)打包
- 放在StreamingAssets目錄下的貼圖和視屏資源會(huì)自動(dòng)打包,且log日志里面沒(méi)有統(tǒng)計(jì)到
- 放在Standard Assets目錄下的貼圖不會(huì)自動(dòng)打包
- Assets下的所有代碼都會(huì)打包
?
三.優(yōu)化方法
相比于Android或者iOS原生App,Unity3D引擎開(kāi)發(fā)的游戲在冷啟動(dòng)時(shí)間上確實(shí)比較長(zhǎng)。三星SM-N9008手機(jī)上的測(cè)試結(jié)果是一個(gè)不算大的項(xiàng)目,如果使用Mono后端編譯,則需要10秒左右的冷啟動(dòng)時(shí)間,而如果使用IL2CPP后端編譯,則冷啟動(dòng)時(shí)間為7秒左右。
1.編譯配置方面優(yōu)化
①.使用IL2CPP進(jìn)行打包
IL2CPP相比于Mono確實(shí)能夠加快冷啟動(dòng)時(shí)間,這是可以預(yù)期的。因?yàn)樵贛ono編譯的情況下,每個(gè).cs文件都是一個(gè)TextAsset文件,而所有的.cs文件都需要在冷啟動(dòng)時(shí)候全部加載到內(nèi)存中,這些碎片化的文件加載操作都會(huì)占用冷啟動(dòng)時(shí)間。關(guān)于冷啟動(dòng)需要加載哪些文件的分析,可以參考Unity3D游戲在啟動(dòng)時(shí)都默認(rèn)加載哪些資源。而IL2CPP會(huì)把所有的C#代碼編譯成C 代碼,然后再進(jìn)行編譯、鏈接等操作,這樣就減少了C#、DLL所帶來(lái)的開(kāi)銷(xiāo)。
②.強(qiáng)烈建議使用IL2CPP后端,如果使用IL2CPP,則可以忽略第6條。
③.攝像機(jī)的clipping planes用到足夠就好,越小回越少drawcall
④.檢查場(chǎng)景中的光源
場(chǎng)景里使用燈光,會(huì)影響了某些物體的陰影,讓drawcall變多,基本上放置一個(gè)environment light以及一個(gè)directional light就行了
?
?
2.代碼優(yōu)化
①.Tolua綁定和Lua資源加載。
這種是每次游戲啟動(dòng)都會(huì)有的,ToLua接口綁定需要一定的時(shí)間,我們?cè)诖_保前期不會(huì)使用Lua的情況下采用多線程的方式進(jìn)行綁定和加載,保證主線程不會(huì)卡住。
②.代碼文件可以編譯成.dll文件
減少大量TextAsset文件導(dǎo)致的碎片化加載時(shí)間。
③.注意設(shè)置Web請(qǐng)求的超時(shí)時(shí)長(zhǎng)
在游戲啟動(dòng)的時(shí)候做了一些hook的事情,會(huì)有Web請(qǐng)求,后來(lái)我們遇到一個(gè)情況是在很多機(jī)器上會(huì)黑屏等待30s甚至60s這樣的時(shí)長(zhǎng),后來(lái)發(fā)現(xiàn)是因?yàn)檫@個(gè)Web請(qǐng)求沒(méi)有設(shè)置超時(shí)時(shí)間,于是使用了機(jī)器默認(rèn)的超時(shí)時(shí)間,在不同設(shè)備上不同,比如紅米2A上會(huì)有接近1分鐘的超時(shí)限制。這個(gè)很坑,只是因?yàn)槟莻€(gè)非必須的Web服務(wù)沒(méi)有正確開(kāi)啟,導(dǎo)致排查了很長(zhǎng)時(shí)間。
Native層增加界面,減少黑屏等待,提升玩家體驗(yàn)。這個(gè)并不能真正解決問(wèn)題,只是一種緩解手段,等到優(yōu)化做到位了,其實(shí)也就不需要了。
④.一些compoment的update可以等loading結(jié)束后才執(zhí)行,減少加載時(shí)每幀的開(kāi)銷(xiāo)
⑤.Transform不能放在for循環(huán),getcompoment也是。
⑥.setactive改造為設(shè)置進(jìn)來(lái)時(shí)判斷是否與之前的值一樣。因?yàn)楸旧韘etactive每次真是調(diào)用都回有g(shù)c
⑦.string不能直接加
⑧.parent用setparent替換。
⑨.協(xié)程用得多,這塊盡量用update或lateupdate替換,因?yàn)閰f(xié)程本身在unity會(huì)創(chuàng)建實(shí)體來(lái)管理,會(huì)產(chǎn)生少量得gc
⑩.減少new waitforsecond的使用并且把他存在一個(gè)變量中
?.特效的order的問(wèn)題,同一個(gè)材質(zhì)的應(yīng)該放在同一個(gè)order下,不同的材質(zhì)一定要放在不同的order下。
?.去掉了加載模型后的卸載行為
?.Aup另一個(gè)線程去做gpu數(shù)據(jù)
?.減少不必要使用的插件
像我為了使用easytouch中的swift手勢(shì)直接導(dǎo)入了一整個(gè)插件,因此有些小功能還是自己寫(xiě)的好,而且還能優(yōu)化安裝包大小,一舉兩得
?.一些重復(fù)加載的資源,可以保存下來(lái)
?.字典的key不能用枚舉
?
3.資源優(yōu)化
①.盡量少的使用Resources方式管理資源,建議使用AssetBundle的方式管理
此項(xiàng)還未測(cè)試,因?yàn)楣境醢娌贿m用AB包方式
Resources目錄下面的所有資源會(huì)在ResourceManager中記錄下來(lái),而ResourceManager就是一個(gè)文件,通常是一個(gè)YAML格式的文本文件。而這個(gè)文件是會(huì)在冷啟動(dòng)時(shí)加載的。所以Resources目錄下面的有越多的資源,那么這個(gè)ResourceManager就會(huì)越大,加載時(shí)間也會(huì)越長(zhǎng)。
使用Resources方式管理資源還有一個(gè)壞處,就是所有的資源都是統(tǒng)一管理的,這樣的資源的管理粒度沒(méi)辦法控制。建議使用AssetBundle的方式管理,這樣可以使用多個(gè)AssetBundle來(lái)管理資源。把在Loading場(chǎng)景中需要的最小資源集放在一個(gè)AssetBundle中,這樣在冷啟動(dòng)時(shí)啟動(dòng)Loading場(chǎng)景時(shí),只需要加載一個(gè)AssetBundle即可。選擇合適的粒度管理AssetBundle,可以在合適的時(shí)候加載某一個(gè)AssetBundle,不使用時(shí)就可以卸載某一個(gè)AssetBundle。
在Loading場(chǎng)景中,添加一個(gè)進(jìn)度條,然后同步加載進(jìn)入主場(chǎng)景所需要的AssetBundle,這樣用戶(hù)就不會(huì)感到等待時(shí)間太煩躁了。同步加載要比異步加載時(shí)間更短。
減少冗余資源和重復(fù)資源方面:
A.Resources目錄下的資源不管是否被引用,都會(huì)打包進(jìn)安裝包,不使用的資源不要放在Resources目錄下
B.不同目錄下的相同資源文件,如果都被引用,那么都會(huì)打包進(jìn)資源包,造成冗余,保證同一個(gè)資源文件在項(xiàng)目中只存放在一個(gè)目錄位置
②.紋理資源選擇合適的壓縮格式進(jìn)行壓縮
紋理資源在游戲中一般是最大的資源,選擇合適的壓縮格式進(jìn)行壓縮,既可以減少內(nèi)存占用,又能夠加快資源的加載速度。壓縮格式的選擇要從顯示效果和壓縮率上進(jìn)行權(quán)衡。一般在Android上使用ETC格式,在iOS上使用PVRTC格式,在某些情況下,可能還可以考慮使用Alpha通道分離技術(shù)進(jìn)行壓縮處理。
(1).嚴(yán)格控制RGBA32和ARGB32紋理的使用,在保證視覺(jué)效果的前提下,盡可能采用“夠用就好”的原則,降低紋理資源的分辨率,以及使用硬件支持的紋理格式。
(2).在硬件格式(ETC、PVRTC)無(wú)法滿(mǎn)足視覺(jué)效果時(shí),RGBA16格式是一種較為理想的折中選擇,既可以增加視覺(jué)效果,又可以保持較低的加載耗時(shí)。
(3).嚴(yán)格檢查紋理資源的Mipmap功能,特別注意UI紋理的Mipmap是否開(kāi)啟。在UWA測(cè)評(píng)過(guò)的項(xiàng)目中,有不少項(xiàng)目的UI紋理均開(kāi)啟了Mipmap功能,不僅造成了內(nèi)存占用上的浪費(fèi),同時(shí)也增加了不小的加載時(shí)間。
(4).ETC2對(duì)于支持OpenGL ES3.0的Android移動(dòng)設(shè)備來(lái)說(shuō),是一個(gè)很好的處理半透明的紋理格式。但是,如果你的游戲需要在大量OpenGL ES2.0的設(shè)備上進(jìn)行運(yùn)行,那么我們不建議使用ETC2格式紋理。因?yàn)椴粌H會(huì)造成大量的內(nèi)存占用(ETC2轉(zhuǎn)成RGBA32),同時(shí)也增加一定的加載時(shí)間。下圖為測(cè)試2中所用的測(cè)試紋理在三星S3和S4設(shè)備上加載性能表現(xiàn)。可以看出,在OpenGL ES2.0設(shè)備上,ETC2格式紋理的加載要明顯高于ETC1格式,且略高于RGBA16格式紋理。因此,建議研發(fā)團(tuán)隊(duì)在項(xiàng)目中謹(jǐn)慎使用ETC2格式紋理。
(5).都去掉alpha通道,作為背景展示的圖片,基本都沒(méi)有透明要求,有特殊要求的則放到atlas里面
a. Loading圖這類(lèi)需要比較精細(xì)的,則把圖片設(shè)置為Automatic TrueColor,設(shè)置真彩色,保證不失真
b. 地圖、縮略圖、UI背景圖等等要求不精細(xì)的,則可以設(shè)置為自動(dòng)壓縮格式(有壓縮情況,都需要圖片寬高尺寸是2的冪,可以在Advance里面設(shè)置toNearest)
(6).關(guān)閉?Read/Write Enabled?設(shè)置
這個(gè)?Read/Write Enabled?的設(shè)置會(huì)造成貼圖在內(nèi)存里變成兩份,一份在?GPU?上一份在?CPU?可以尋址的內(nèi)存上。這是因?yàn)榇蠖鄶?shù)平臺(tái),把數(shù)據(jù)從?GPU?內(nèi)存讀回?CPU?很慢。從?GPU?內(nèi)存讀取一張貼圖到暫存區(qū)給?CPU?程序用(例如:Texture.GetPixel)會(huì)導(dǎo)致效能很差。這個(gè)設(shè)定在?Unity?里預(yù)設(shè)是關(guān)閉的,但要避免誤勾這個(gè)選項(xiàng)。?
?
注意:ios下會(huì)自動(dòng)把圖片寬高拉伸為2的冪次方尺寸,這樣會(huì)導(dǎo)致圖片顯示失真,解決辦法是制作圖片的時(shí)候就保證是2的冪大小。如果圖片顯示的區(qū)域確實(shí)不能做出2的冪大小,可以用補(bǔ)黑邊的方式把圖片做出2的冪大小,設(shè)置圖片的時(shí)候,就需要調(diào)整圖片的UV
要點(diǎn):android下,帶alpha通道的圖片,自動(dòng)壓縮是以ETC2 8bit的方式壓縮的,不帶alpha通道,是壓縮成ETC 4bit的格式(ETC2 支持alpha通道),ios下是壓縮成PVRTC 4格式。手機(jī)硬件對(duì)各種格式圖片的加載效率不一樣,RGBA32是最慢的。所以需要對(duì)圖片進(jìn)行處理,改壓縮方式,ETC和pvr是加載最快的。
③.模型優(yōu)化
(1).網(wǎng)格資源
- 在保證視覺(jué)效果的前提下,盡可能采用“夠用就好”的原則,即降低網(wǎng)格資源的頂點(diǎn)數(shù)量和面片數(shù)量;
- 研發(fā)團(tuán)隊(duì)對(duì)于頂點(diǎn)屬性的使用需謹(jǐn)慎處理。通過(guò)以上分析可以看出,頂點(diǎn)屬性越多,則內(nèi)存占用越高,加載時(shí)間越長(zhǎng);
- 如果在項(xiàng)目運(yùn)行過(guò)程中對(duì)網(wǎng)格資源數(shù)據(jù)不進(jìn)行讀寫(xiě)操作(比如Morphing動(dòng)畫(huà)等),那么建議將Read/Write功能關(guān)閉,既可以提升加載效率,又可以大幅度降低內(nèi)存占用。
(2).LOD層級(jí)細(xì)節(jié)技術(shù)
? ? ? ?此技術(shù)需要美工的配合,提供給程序多個(gè)不同三角面數(shù)的模型
在場(chǎng)景中新建一個(gè)空的游戲物體,并添加LOD Group組件,如下圖所示:
并將美工提供的三種不同精度的模型按照精度的大小依次拖入到LOD0、LOD1、LOD2中
此時(shí),場(chǎng)景中渲染顯示的模型會(huì)根據(jù)相機(jī)與模型的距離進(jìn)行切換顯示,具體的切換顯示距離可拖動(dòng)組件中的條形框大小進(jìn)行自定義,這樣便達(dá)到了近處渲染精模,遠(yuǎn)處渲染粗模甚至不渲染來(lái)減少GPU消耗的目的
? ? ? ? ? ? ? ? ??
(3).OcclusionCulling遮擋剔除技術(shù)
? ? ? ?當(dāng)場(chǎng)景中有大量模型需要渲染時(shí),應(yīng)用遮擋剔除可實(shí)現(xiàn)減少DrawCall提升性能的效果
首先選中所有需要進(jìn)行遮擋剔除的模型,并設(shè)置其occluder(遮擋體)和occludee(被遮擋體),有的物體可以是遮擋體同時(shí)也是被遮擋體。
接下來(lái)Window / Occlusion Culling 打開(kāi)遮擋剔除面板如下圖:
選中遮擋剔除選項(xiàng),烘焙
烘焙完成后,設(shè)置好顯示視野的相機(jī)
(4).Lightmapping光照貼圖技術(shù)
首先將需要進(jìn)行光照貼圖的游戲物體設(shè)置為L(zhǎng)ightmap Static
其次將用于光照貼圖的所有光源設(shè)置為Baked模式
最后Window / Lighting 打開(kāi)燈光面板,進(jìn)行烘焙,面板如下
? 其中Build后會(huì)在當(dāng)前場(chǎng)景所在的文件夾中生成一個(gè)光照貼圖文件,我們也可以點(diǎn)擊Clear Baked Data 按鈕進(jìn)行光照貼圖的清理操作
之后無(wú)論場(chǎng)景中的光源是否激活,均顯示光照效果,效果圖如下:
·
(5).Mesh合并
?當(dāng)場(chǎng)景中模型非常多,不妨試一下模型合并技術(shù),可以在3dMax或其他建模軟件上進(jìn)行操作,也可在Unity中進(jìn)行操作,這里我僅介紹Unity中的模型合并方法。
前提:合并的物體必須是相同的材質(zhì),否則合并之后賦值多個(gè)材質(zhì)并不能起到優(yōu)化作用
首先,將下述代碼放在Assets / Editor 文件夾下
其次,在場(chǎng)景中需要合并的模型放在一個(gè)空物體下
然后,點(diǎn)擊選中空物體并點(diǎn)擊上方的菜單欄按鈕MeshCombine / CombineChildren進(jìn)行合并所有子物體Mesh
最后,自行更改模型中的材質(zhì),位置等參數(shù)即可
using UnityEngine; using System.Collections; using UnityEditor;public class CombineMesh : MonoBehaviour {//菜單按鈕靜態(tài)觸發(fā)[MenuItem( "MeshCombine/CombineChildren")] static void CreatMeshCombine(){//獲取到當(dāng)前點(diǎn)擊的游戲物體Transform tSelect = (Selection.activeGameObject).transform;//如果當(dāng)前點(diǎn)擊的游戲物體無(wú)子物體,則無(wú)操作if (tSelect.childCount < 1){return;}//確保當(dāng)前點(diǎn)擊的游戲物體身上有MeshFilter組件if (!tSelect.GetComponent<MeshFilter>()){tSelect.gameObject.AddComponent<MeshFilter>();}//確保當(dāng)前點(diǎn)擊的游戲物體身上有MeshRenderer組件if (!tSelect.GetComponent<MeshRenderer>()){tSelect.gameObject.AddComponent<MeshRenderer>();}//獲取到所有子物體的MeshFilter組件MeshFilter[] tFilters = tSelect.GetComponentsInChildren<MeshFilter>();//根據(jù)所有MeshFilter組件的個(gè)數(shù)申請(qǐng)一個(gè)用于Mesh聯(lián)合的類(lèi)存儲(chǔ)信息CombineInstance[] tCombiners = new CombineInstance[tFilters.Length];//遍歷所有子物體的網(wǎng)格信息進(jìn)行存儲(chǔ)for (int i = 0; i < tFilters .Length ; i++){//記錄網(wǎng)格tCombiners[i].mesh = tFilters[i].sharedMesh;//記錄位置tCombiners[i].transform = tFilters[i].transform.localToWorldMatrix;}//新申請(qǐng)一個(gè)網(wǎng)格用于顯示組合后的游戲物體Mesh tFinalMesh = new Mesh();//重命名MeshtFinalMesh.name = "tCombineMesh";//調(diào)用Unity內(nèi)置方法組合新Mesh網(wǎng)格tFinalMesh.CombineMeshes(tCombiners);//賦值組合后的Mesh網(wǎng)格給選中的物體tSelect.GetComponent<MeshFilter>().sharedMesh = tFinalMesh;//賦值新的材質(zhì)tSelect.GetComponent<MeshRenderer>().material = new Material(Shader.Find("VertexLit"));}}效果圖如下:
?
(6) 去掉多余的mesh
(8).骨骼動(dòng)畫(huà)開(kāi)啟optimizeGameObjects選項(xiàng),減少骨骼運(yùn)算。
??ModelImporter.optimizeGameObjects?能夠優(yōu)化骨骼動(dòng)畫(huà),將無(wú)用的骨骼合并,實(shí)際測(cè)試發(fā)現(xiàn),設(shè)置此選項(xiàng)后的蒙皮骨骼動(dòng)畫(huà)模型,不受動(dòng)態(tài)縮放影響,只能保持導(dǎo)入的大小,大規(guī)模同屏角色肯定是效率有明顯的影響,但是對(duì)于動(dòng)態(tài)改變模型大小的需求該方法不太適用。
打勾后所有的骨架對(duì)應(yīng)的?Transform?結(jié)構(gòu)都會(huì)被移除,如果模型骨架結(jié)構(gòu)中有特定的部位需要露出方便控制(例如模型的手部要用來(lái)握住武器),則可以把它列在“ExtraTransforms”白名單中。?
?
(9).關(guān)閉?Read/Write Enabled?設(shè)置?
當(dāng)項(xiàng)目執(zhí)行時(shí)想用程序來(lái)修改?Mesh,或者如果?Mesh?要用作?MeshCollider?的話(huà),這里需要打勾。反之如果模型沒(méi)用在MeshCollider,也沒(méi)用程序來(lái)修改?Mesh?的話(huà),關(guān)閉這里可以省下一半的內(nèi)存。?
(10).使用Mesh壓縮?
開(kāi)啟?Mesh compression?選項(xiàng)會(huì)縮短用來(lái)表示模型數(shù)據(jù)不同信道的浮點(diǎn)數(shù)字元長(zhǎng)度,這會(huì)移除一定的精確度并可能造成可見(jiàn)的變化,使用這個(gè)之前最好先讓美術(shù)檢查過(guò)這種損失在允許范圍內(nèi)。?
各個(gè)壓縮等級(jí)使用的位長(zhǎng)度在?ModelImporterMeshCompression?腳本里有介紹。?
請(qǐng)記得,可以針對(duì)不同信道使用不同等級(jí)的壓縮,所以項(xiàng)目可以只針對(duì)切線向量(Tangent)和法向量(Normal)壓縮但不壓縮?UV?和頂點(diǎn)位置。
?
④.音樂(lè)加載優(yōu)化
(1).Mac / PC 適用于 Ogg Vorbis格式音頻,而Mp3適用于移動(dòng)端,不過(guò)音質(zhì)會(huì)下降
? ? ? ? ? ? ? 長(zhǎng)時(shí)間音樂(lè)(背景音樂(lè))壓縮格式:mp3
短時(shí)間音樂(lè)(攻擊等等)一般不壓縮存儲(chǔ)格式為:wav
(2).加載模式
?
Decompress On Load:適用于小文件
Compressed in Memory:使用于大文件
Streaming:以流的形式便加載邊播放(對(duì)CPU消耗較大一般不采用)
如果是交互的音效應(yīng)該不能壓縮,不然因?yàn)閡nity要解壓,需要耗時(shí)所以點(diǎn)擊時(shí)不能做到實(shí)時(shí)。關(guān)鍵再選擇PCM
?
(3) .降低音頻的取樣
調(diào)低取樣能進(jìn)一步降低內(nèi)存消耗和最終項(xiàng)目的大小,可以和音效設(shè)計(jì)師協(xié)調(diào)找出最小最能接受的音源質(zhì)量。參考SetCompressionBitrate。?
(4).強(qiáng)制音效用單聲道?
只有少數(shù)的手機(jī)裝置真的有立體聲喇叭,而將音效強(qiáng)制設(shè)定為單聲道能讓內(nèi)存的消耗減半。就算游戲會(huì)輸出部份的立體聲,有些單聲道像是?UI?音效還是可以開(kāi)啟這個(gè)選項(xiàng)。
(5).采用平臺(tái)支持的壓縮設(shè)定?
采用硬件支持的音源壓縮格式。所有的iOS設(shè)備都有?MP3?硬件解壓縮能力,而大多數(shù)的?Android?設(shè)備都有支持?Vorbis。
此外,可以直接將未壓縮的聲音文件導(dǎo)入?Unity?里,因?yàn)?Unity?會(huì)在打包項(xiàng)目時(shí)會(huì)重新壓縮。所以不需要先壓縮再導(dǎo)入U(xiǎn)nity,這只會(huì)降低音效質(zhì)量。
?
⑤.資源重復(fù)利用
unity scrollview 優(yōu)化 高效重復(fù)利用 避免大量初始化時(shí)間過(guò)長(zhǎng)
類(lèi)似該文章中可以進(jìn)行加載顯示部分,然后再根據(jù)操作進(jìn)行循環(huán)利用(可以使用資源池實(shí)現(xiàn))?
?⑥.Shader編譯時(shí)間過(guò)長(zhǎng)。
如果只有游戲安裝之后第一次啟動(dòng)時(shí)間過(guò)長(zhǎng),一個(gè)很大的可能是shader編譯,之后游戲啟動(dòng)因?yàn)橛辛薈ache所以會(huì)快很多。這種情況的話(huà)建議查看下Always Include的Shader內(nèi)容和變體,使用shadervariantcollection等方案替代。
(1)、Shader資源的物理體積與內(nèi)存占用雖然很小,但其加載耗時(shí)開(kāi)銷(xiāo)的CPU占用很高,這主要是因?yàn)镾hader的解析CPU開(kāi)銷(xiāo)很高,成為了Shader資源加載的性能瓶頸;
(2)、Mobile/Particles Additive在解析方面的耗時(shí)遠(yuǎn)小于Mobile/Diffuse、Mobile/Bumped Diffsue甚至Mobile/VertexLit;
(3)、除Mobile/Particles Additive外,其他三個(gè)主流Shader在加載時(shí)均會(huì)造成明顯的降幀,甚至卡頓。因此,研發(fā)團(tuán)隊(duì)?wèi)?yīng)盡可能避免在非切換場(chǎng)景時(shí)刻進(jìn)行Shader的加載操作;
(4)、盡量減少?gòu)?fù)雜的數(shù)學(xué)運(yùn)算,盡量減少Discard操作
(5)、隨著硬件設(shè)備性能的提升,其解析效率差異越來(lái)越不明顯。
對(duì)于Shader資源的管理建議如下:
(1)、在保證渲染效果和項(xiàng)目需求的情況下,盡可能降低Shader的Keyword數(shù)量,以提升Shader的加載效率;
(2)、對(duì)于簡(jiǎn)單Shader,可嘗試去除Fallback操作,該方法非常適合于目前正在大量使用的Mobile/Diffuse、Mobile/Bumped Diffuse等Built-in Shader;
(3)、盡可能對(duì)Shader進(jìn)行單獨(dú)、依賴(lài)關(guān)系打包并對(duì)其進(jìn)行預(yù)加載,以降低后續(xù)不必要的加載開(kāi)銷(xiāo)。
?
⑦.調(diào)整層級(jí),把相同的altas放在一個(gè)順序的層級(jí)里
調(diào)整前 :
?
調(diào)整后 :
?
如果遇上調(diào)整層級(jí)還是具有相同材質(zhì)的靜態(tài)物體并沒(méi)放到一個(gè)drawcall,還是一個(gè)個(gè)繪制
?
?看了下這幾個(gè)繪制的物體receive shadow都是勾選的,所以問(wèn)題應(yīng)該出在了within the shadow distance這里。就是這些物體受到了不同的陰影影響。比如2塊石頭,一塊石頭在樹(shù)下,受到了樹(shù)影子的影響,被放到一個(gè)drawcall里,另一塊石頭就是沒(méi)有受到任何遮擋,所以直接被放在一個(gè)drawcall。它們就不能在一個(gè)drawcall里了。
因此要判斷是否需要陰影進(jìn)行取出陰影:
?
cast shadows 設(shè)為off,取消勾選receive shadows。如果不需要讓它影響lightmap,取消勾選lightmap static
⑦.資源審查
對(duì)于較大規(guī)模的項(xiàng)目,最好準(zhǔn)備一道自動(dòng)的防線防范人為失誤。例如寫(xiě)一段簡(jiǎn)單的檢查程序確保沒(méi)有任何人能在項(xiàng)目加入一張沒(méi)壓縮的?4K?貼圖。?
或許你會(huì)覺(jué)得不可能,但這問(wèn)題我們真的很常見(jiàn)。沒(méi)有壓縮的?4K?貼圖會(huì)占用大約?60mb?的內(nèi)存空間,在低端的手機(jī)設(shè)備(例如?iPhone 4s)上,整個(gè)項(xiàng)目用掉超過(guò)?180mb~200mb?就會(huì)很危險(xiǎn)。有時(shí)候你的游戲在好的手機(jī)上跑沒(méi)問(wèn)題,在差的手機(jī)上跑會(huì)宕機(jī),不一定是硬件的問(wèn)題。如果犯這種錯(cuò)誤,這張貼圖會(huì)無(wú)端占用應(yīng)用程序四分之一到三分之一的可用內(nèi)存,造成很難追蹤的內(nèi)存不足錯(cuò)誤。?
⑧.資源后處理
Unity?編輯器里的?AssetPostprocessor?類(lèi)別可以用在?Unity?項(xiàng)目上實(shí)行某些基本限制。這個(gè)類(lèi)別在資源導(dǎo)入時(shí)會(huì)收到一個(gè)回調(diào)。使用方法即繼承?AssetPostprocessor?并實(shí)作一個(gè)或多個(gè)?OnPreprocess?方法,重要的包含:?
OnPreprocessTexture?
OnPreprocessModel?
OnPreprocessAnimation?
OnPreprocessAudio?
public class ReadOnlyModelPostprocessor : AssetPostprocessor {public void OnPreprocessModel() {ModelImporter modelImporter = (ModelImporter)assetImporter;if(modelImporter.isReadable) {modelImporter.isReadable = false;modelImporter.SaveAndReimport();}} }?這是一個(gè)簡(jiǎn)單的?AssetPostprocessor?限制規(guī)則范例?
每當(dāng)導(dǎo)入模型到項(xiàng)目或模型的導(dǎo)入設(shè)定(Import settings)被修改時(shí)會(huì)呼叫這個(gè)類(lèi)別,這里程序只是檢查可否讀寫(xiě)模型的設(shè)置?isReadable?屬性,如果是?true?就會(huì)改為?false,存盤(pán)后重新導(dǎo)入資源。?
請(qǐng)注意,呼叫?SaveAndReimport?會(huì)導(dǎo)致這段程序會(huì)被再次呼叫!但由于設(shè)置已經(jīng)被改為?false,所以不會(huì)無(wú)窮遞歸下去。?
?
4.UI優(yōu)化
①.有一些ui上掛了剛體,但其實(shí)ui是沒(méi)必要用剛體的,增加額外的組件會(huì)增加額外的開(kāi)銷(xiāo)。(ngui會(huì)加上rigidbody)
②.移除ui圖片的read/write,mipmap
?
5.設(shè)計(jì)優(yōu)化
①.啟動(dòng)場(chǎng)景不放模型,只放UI
公司初版APP模型很大,也是放在本地,但是我在第一個(gè)場(chǎng)景初始化的時(shí)候加載了模型,更改之后快了10s左右
②.項(xiàng)目中添加一個(gè)Loading場(chǎng)景,這個(gè)場(chǎng)景會(huì)是游戲啟動(dòng)的第一個(gè)場(chǎng)景。
在Loading場(chǎng)景中盡量少的依賴(lài),盡量少的紋理依賴(lài)、AssetBundle依賴(lài)、代碼依賴(lài),總之,這個(gè)Loading場(chǎng)景一定要盡量少的依賴(lài),這個(gè)場(chǎng)景一定要盡量簡(jiǎn)單,這樣才能保證盡快的加載速度。
?
6.內(nèi)存優(yōu)化
在當(dāng)下的手機(jī)及平板硬件設(shè)備條件下,操作系統(tǒng)留給應(yīng)用的可用內(nèi)存并不多,大約只有 500M 左右。
和 PC 環(huán)境不同,手機(jī)上是交換分區(qū)的機(jī)制來(lái)對(duì)應(yīng)一些臨時(shí)突發(fā)性?xún)?nèi)存需求的。而手機(jī)必須保證一些系統(tǒng)服務(wù)(某些高優(yōu)先級(jí)后臺(tái)業(yè)務(wù))的運(yùn)行,所以在接電話(huà)、收取推送等等意外任務(wù)發(fā)生時(shí),有可能多占用一些內(nèi)存,導(dǎo)致操作系統(tǒng)殺掉前臺(tái)任務(wù)讓出資源。根據(jù)實(shí)際測(cè)試,游戲想跑在當(dāng)前主流高端手機(jī)上必須把自己的內(nèi)存占用峰值控制在 400M 內(nèi)存以下,350 M 會(huì)是一個(gè)合理的值
①.設(shè)定了若干包圍盒,勾畫(huà)出一塊塊小區(qū)域。一旦玩家離開(kāi)包圍盒太遠(yuǎn),程序就把包圍盒里面的物件卸載出內(nèi)存。包圍盒略微擴(kuò)大,允許包圍盒重疊,并可以用多個(gè)包圍盒來(lái)定義一個(gè)區(qū)域。同一個(gè)場(chǎng)景物件只可以屬于一個(gè)區(qū)域,即使它的位置在多個(gè)區(qū)域內(nèi)。(區(qū)域可以重疊)
?所有物件都標(biāo)記分類(lèi)出外觀物件和細(xì)節(jié)物件。比如一個(gè)城市的城墻就是外觀物件,而城內(nèi)的所有東西都是細(xì)節(jié)物件;一片樹(shù)林的大顆植物是外觀物件,地面的花花草草是細(xì)節(jié)物件。一般情況下,大部分物件都默認(rèn)是細(xì)節(jié)物件,只有少數(shù)需要遠(yuǎn)觀的才標(biāo)記成外觀。這點(diǎn),其實(shí)原本就做了視距分層,只不過(guò)是為了在渲染時(shí)做顯示剔除用的,并沒(méi)有用于控制內(nèi)存。而這次,需要對(duì)外觀物件和細(xì)節(jié)物件單獨(dú)打包分類(lèi),便于分開(kāi)卸載。
當(dāng)玩家處于一個(gè)區(qū)域內(nèi)部時(shí),必須保證這個(gè)區(qū)域的外觀物件和細(xì)節(jié)物件都加載到內(nèi)存。如果之前并不在內(nèi)存,也需要開(kāi)啟異步加載的流程。當(dāng)一個(gè)玩家距離另一個(gè)區(qū)域比較近時(shí),只需要確保該區(qū)域的外觀物件在內(nèi)存即可,可以卸載任何不在區(qū)域的細(xì)節(jié)物件。
②.放置Mono內(nèi)存泄漏
(1)出現(xiàn)原因?
1. “忘記”清除對(duì)該無(wú)用對(duì)象的引用
并非只有顯示調(diào)用new才會(huì)分配內(nèi)存,很多隱式的分配是不容易被發(fā)現(xiàn)的,例如產(chǎn)生一個(gè)List來(lái)存儲(chǔ)數(shù)據(jù),緩存了服務(wù)器下發(fā)的一份配置,產(chǎn)生一個(gè)字符串等等,這些操作都會(huì)產(chǎn)生內(nèi)存的分配。你分配幾十K,他分配幾十K,一會(huì)兒內(nèi)存就沒(méi)了。?
其次,有一點(diǎn)需要說(shuō)明的是,在Unity環(huán)境下,Mono堆內(nèi)存的占用,是只會(huì)增加不會(huì)減少的。具體來(lái)說(shuō),可以將Mono堆,理解為一個(gè)內(nèi)存池,每次Mono內(nèi)存的申請(qǐng),都會(huì)在池內(nèi)進(jìn)行分配;釋放的時(shí)候,也是歸還給池,而不會(huì)歸還給操作系統(tǒng)。如果某次分配,發(fā)現(xiàn)池內(nèi)內(nèi)存不夠了,則會(huì)對(duì)池進(jìn)行擴(kuò)建——向操作系統(tǒng)申請(qǐng)更多的內(nèi)存擴(kuò)大池以滿(mǎn)足該次的內(nèi)存分配。需要注意的是,每次對(duì)池的擴(kuò)建,都是一次較大的內(nèi)存分配,每次擴(kuò)建,都會(huì)將池?cái)U(kuò)大6-10M左右(此處無(wú)官方數(shù)據(jù),是觀察所得)。
2.資源中的泄漏 – Native內(nèi)存泄漏(資源加載之后占有了內(nèi)存,但是在資源不用之后,沒(méi)有將資源卸載導(dǎo)致內(nèi)存的無(wú)謂占用。?)
Unity的內(nèi)存回收是需要主動(dòng)觸發(fā)的(Resources.UnloadUnusedAssets()),GC也提供了同樣的接口GC.Collect()?用來(lái)主動(dòng)觸發(fā)垃圾回收,Resources.UnloadUnusedAssets()內(nèi)部本身就會(huì)調(diào)用GC.Collect(),Unity還提供了另外一個(gè)更加暴力的方式——Resources.UnloadAsset()來(lái)卸載資源,但是這個(gè)接口無(wú)論資源是不是“垃圾”,都會(huì)直接刪除,是一個(gè)很危險(xiǎn)的接口,建議確定資源不使用的情況下,再調(diào)用該接口。為了避免游戲卡頓,建議在加載環(huán)節(jié)來(lái)處理垃圾回收的操作。
再來(lái)看一下為什么會(huì)有資源的泄漏。首先和代碼側(cè)的泄漏一樣,由于“存在該釋放卻沒(méi)有釋放的錯(cuò)誤引用”,導(dǎo)致回收機(jī)制認(rèn)為目標(biāo)對(duì)象不是“垃圾”,以至于不能被回收,這也是最常見(jiàn)的一種情況。
針對(duì)資源,還有一種典型的泄漏情況。由于資源卸載是主動(dòng)觸發(fā)的,那么清除對(duì)資源引用的時(shí)機(jī)就顯得尤為重要?,F(xiàn)在游戲的邏輯趨于復(fù)雜化,同時(shí)如果有新成員加入項(xiàng)目組,也未必能夠清楚地了解所有資源管理的細(xì)節(jié),如果“在觸發(fā)了資源卸載之后,才清除對(duì)資源引用”,同樣也會(huì)出現(xiàn)內(nèi)存泄漏了。
還有一種資源上的泄漏,是因?yàn)閁nity的一些接口在調(diào)用時(shí)會(huì)產(chǎn)生一份拷貝(例如Renderer.Material參考https://docs.unity3d.com/ScriptReference/Renderer-material.html),如果在使用上不注意的話(huà),運(yùn)行時(shí)會(huì)產(chǎn)生較多的資源拷貝,造成內(nèi)存的無(wú)端浪費(fèi)。
?
具體請(qǐng)看 :?Unity中的內(nèi)存泄漏
?
參考:
App冷啟動(dòng)、熱啟動(dòng)介紹以及優(yōu)化啟動(dòng)的實(shí)現(xiàn)方式,解決啟動(dòng)白屏問(wèn)題
在Unity3D游戲如何加快冷啟動(dòng)時(shí)間
Unity啟動(dòng)耗時(shí)優(yōu)化
iOS 優(yōu)化程序冷啟動(dòng)時(shí)間
關(guān)于Unity加載優(yōu)化,你可能遇到這些問(wèn)題
unity3d 加載優(yōu)化建議 總結(jié) from 侑虎科技
unity scrollview 優(yōu)化 高效重復(fù)利用 避免大量初始化時(shí)間過(guò)長(zhǎng)
關(guān)于Unity性能優(yōu)化的一些方法
unity加載優(yōu)化小結(jié)
批處理優(yōu)化(官方鏈接)
Unity3D性能優(yōu)化最佳實(shí)踐(四)資源審查
unity-Profiler調(diào)試Android的正確姿勢(shì)(mumu模擬器)
unity 打包編譯記錄
Unity3D 的大場(chǎng)景內(nèi)存優(yōu)化
Unity中的內(nèi)存泄漏
資源加載性能測(cè)試代碼
總結(jié)
以上是生活随笔為你收集整理的unity优化冷启动时间/加载时间总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 台式计算机mtbf,电子产品整机MTBF
- 下一篇: 【DiscuzX2】DiscuzX2的u