性能調(diào)優(yōu)屯蹦,一直是游戲上線之前的很重要的一個(gè)環(huán)節(jié), 游戲幀率過低胆数,手機(jī)發(fā)燙, 低端機(jī)上跑不起來等, 這些都需要來做優(yōu)化,今天我們來給大家分享Unity做性能調(diào)優(yōu)的指導(dǎo)思想與解決方案匈庭。
這里有個(gè)unity學(xué)習(xí)交流小組點(diǎn)擊可以直接加入仰禀,一起學(xué)習(xí)交流吧
性能調(diào)優(yōu)的指導(dǎo)思想
接觸過很多剛做性能調(diào)優(yōu)的小伙伴,他們做性能調(diào)優(yōu)最大的問題一開始就通過猜測(cè)秦叛,推斷來做性能調(diào)優(yōu)晦溪,缺乏一個(gè)做性能優(yōu)化的系統(tǒng)指導(dǎo)流程, 導(dǎo)致優(yōu)化的效果不好。性能調(diào)優(yōu)首先要分析問題挣跋,定位問題三圆,證明是這塊有問題后再對(duì)癥下藥,著手優(yōu)化,拿出解決對(duì)策避咆。沒有證明問題之前舟肉,不要隨便動(dòng)手優(yōu)化,就像醫(yī)生查库,看病做手術(shù)前先做檢查路媚。不確定問題就隨便開刀,那是極不負(fù)責(zé)任的做法樊销。
大家可以回想一下整慎,當(dāng)幀率低的時(shí)候,你馬上就是去查Drawcall,去優(yōu)化降低Drawcall,這里我想說围苫,做性能優(yōu)化之前裤园,先定位,證明確實(shí)是Drawcall的問題導(dǎo)致性能下降,才動(dòng)手剂府。如何來定位問題比然,找出引起問題的代碼或物體呢?接下來給大家介紹一些方法周循。
(1)對(duì)比法
例如, 剛開始的時(shí)候幀率是60FPS强法,同一個(gè)場(chǎng)景運(yùn)行一段時(shí)間以后是30FPS万俗,如何優(yōu)化,像這種符合很明顯的對(duì)比場(chǎng)景饮怯,我們可以通過前后對(duì)比闰歪,來找出60FPS,30FPS蓖墅,最大的變化库倘。一般可以通過打開stats, 來觀察前后主要的變化,main thread耗時(shí)论矾,render thread耗時(shí), 三角形面數(shù)教翩,內(nèi)存等信息,看看前后明顯發(fā)生的變化贪壳”ヒ冢看到數(shù)據(jù)變化以后,再來思考整個(gè)過程中代碼做了哪些事情闰靴,出現(xiàn)過哪些物體彪笼,最可能出的問題的地方,然后再證明, 只有證明了問題的存在蚂且,再著手優(yōu)化配猫。
(2)隔離法
這個(gè)是我經(jīng)常用的一個(gè)方法, 就是隔離可疑區(qū)域和代碼,然后比較杏死,逐步排查泵肄,縮小問題范圍。隔離法其實(shí)是非常好的方法淑翼,看上去很笨凡伊,很慢,但其實(shí)效率遠(yuǎn)比你想像的要好窒舟。比如系忙,場(chǎng)景的物體過多,這個(gè)問題惠豺,那么我就可以采取隔離方法银还,先減少掉一倍,看效果洁墙。某個(gè)代碼引發(fā)了幀率下降蛹疯,可以逐步的注釋掉代碼,來觀察結(jié)果热监,隔離的時(shí)候捺弦,可以采用二分查找,一半一半的排查。排查范圍很快被縮小,問題也就精確的定位了列吼。
(3)反經(jīng)驗(yàn)法
上面介紹了常用的兩種方法幽崩,定位問題,還有其他的一些方法寞钥,但我更想說的就是反經(jīng)驗(yàn)法慌申。你沒看錯(cuò),反經(jīng)驗(yàn)理郑,在性能優(yōu)化的時(shí)候蹄溉,不要過分相信經(jīng)驗(yàn),一步一步的逐步分析您炉,有條不穩(wěn)柒爵。不管什么問題,按部就班赚爵,不要根據(jù)經(jīng)驗(yàn)棉胀,武斷的下結(jié)論,要嚴(yán)格證明問題所在后再動(dòng)手, 很多小伙伴遇到性能問題后囱晴,把問題簡單的描述一下膏蚓,去請(qǐng)教一個(gè)經(jīng)驗(yàn)豐富的人瓢谢,問他可能是哪方面的問題畸写,根據(jù)他的猜測(cè),你來優(yōu)化氓扛。這種方式是很難做好你項(xiàng)目的性能優(yōu)化的枯芬,項(xiàng)目和項(xiàng)目都不一樣,連具體的問題都沒有定位采郎,你去請(qǐng)教經(jīng)驗(yàn)豐富的老者千所,從老者的角度來說也無法幫到你。不要迷信經(jīng)驗(yàn)蒜埋,在動(dòng)手前一定要定位好誰的問題淫痰,然后才能針對(duì)具體問題下對(duì)策。
優(yōu)化架構(gòu), 標(biāo)準(zhǔn)規(guī)范化開發(fā)流程
好的框架設(shè)計(jì)整份,不僅讓大家能很好的在一起工作待错,同時(shí)更方便我們快速的反應(yīng)和定位問題。你的項(xiàng)目不好定位問題烈评,那么一定是框架設(shè)計(jì)做的不好火俄。所以開始做項(xiàng)目的時(shí)候,框架設(shè)計(jì)要花點(diǎn)時(shí)間讲冠,模塊盡可能的獨(dú)立瓜客,模塊入口盡量清晰,整個(gè)框架設(shè)計(jì)能很好的隔離錯(cuò)誤的蔓延。資源視圖與邏輯代碼分離,游戲數(shù)據(jù)與代碼邏輯分離谱仪。這些都有助于快速的定位問題,比如我要驗(yàn)證是否物體過多玻熙,導(dǎo)致性能問題,只要在表格上配置一下芽卿,少放一些物體就可以驗(yàn)證揭芍,如果覺得是某個(gè)功能,導(dǎo)致消耗CPU卸例,可以把物體的這個(gè)功能的組件關(guān)閉或不添加称杨,比如懷疑怪物AI,可以注釋掉添加怪物AI的組件,來證明筷转。好的框架設(shè)計(jì),在定位問題的時(shí)候姑原,就變得非常簡單。如果是ECS呜舒,定位會(huì)更加簡單锭汛,內(nèi)存看Entity與資源,算法性能看System與物體規(guī)南龋……
接下來要給大家介紹的是我認(rèn)為最重要的經(jīng)驗(yàn)唤殴,就是標(biāo)準(zhǔn)化,規(guī)范化項(xiàng)目開發(fā)進(jìn)度和流程, 把性能問題一開始就放到日常項(xiàng)目開發(fā)中。我?guī)ы?xiàng)目的時(shí)候到腥,每個(gè)禮拜至少做一次發(fā)布版本的測(cè)試朵逝,包含各個(gè)平臺(tái),不同的手機(jī)等乡范。嚴(yán)格監(jiān)測(cè)性能各項(xiàng)數(shù)據(jù)配名,哪個(gè)禮拜出現(xiàn)性能問題,馬上可以回溯,復(fù)盤數(shù)據(jù)晋辆,著手摸清楚并解決渠脉,盡快修正。項(xiàng)目立項(xiàng)后瓶佳,盡快的驗(yàn)證核心玩法極限時(shí)的性能開銷與測(cè)試芋膘。不要等游戲項(xiàng)目做完了,才去驗(yàn)證霸饲,在設(shè)計(jì)初期驗(yàn)證完成后为朋,針對(duì)一些性能問題組織技術(shù)公關(guān),可能還要修改策劃需求和玩法, 早期把性能問題盡快越早摸清楚贴彼,是確保整個(gè)項(xiàng)目成功上線的關(guān)鍵潜腻,不要等到上線了才到各平臺(tái)做測(cè)試,那個(gè)時(shí)候功能多了器仗,不知道有些問題是從什么時(shí)候開始就有的融涣。標(biāo)準(zhǔn)的嚴(yán)謹(jǐn)?shù)拈_發(fā)流程童番,伴隨項(xiàng)目監(jiān)控性能數(shù)據(jù),盡快驗(yàn)證核心玩法威鹿,提前引入測(cè)試, 讓我們整個(gè)項(xiàng)目開發(fā)做到有問題盡早發(fā)現(xiàn),盡早糾正剃斧。
Unity 性能優(yōu)化方法集錦
講完指導(dǎo)思想,和開發(fā)流程這些宏觀問題后, 我們?cè)賮碛懻撘恍┚唧w問題的常用的優(yōu)化方法忽你。
(1)包體體積優(yōu)化:
聲音文件優(yōu)化
將wav幼东,壓縮成mp3或ogg, 最好是ogg,沒有版權(quán)問題, 將多聲道變成單聲道。改變聲音的采樣率與碼率科雳,減少聲音文件體積根蟹。
字體文件優(yōu)化
盡量多使用系統(tǒng)字庫,這樣不用額外帶字體文件糟秘〖虼可以使用一些位圖字庫,來替代額外的字庫尿赚。如果你的文本內(nèi)容是固定的散庶,可以對(duì)字庫進(jìn)行裁剪,把不用的字從字庫里面刪除掉,減少自帶字庫的體積凌净。
貼圖文件大小優(yōu)化
將png轉(zhuǎn)jpg, 并使用圖片壓縮軟件悲龟,壓縮貼圖體積, 盡量減少圖片數(shù)目,復(fù)用圖片冰寻,盡量能使用顏色等代碼的方式來代替貼圖须教。
3D模型文件
根據(jù)需求適當(dāng)降低模型面數(shù), 去掉多余不用的數(shù)據(jù), 可以通過法線貼圖,高度貼圖等將低模做出高模的效果, 合并貼圖通道數(shù)據(jù)(PBR工作流中,將金屬度,粗糙度,環(huán)境遮擋放一個(gè)紋理里面, 將數(shù)據(jù)合并到貼圖不用的通道性雄,比如Albedo貼圖没卸,Alpha通道不用羹奉,可以存放環(huán)境遮擋等秒旋,節(jié)約貼圖數(shù)目)。
將資源ab包化
把所有的資源分成一個(gè)一個(gè)的ab包诀拭,ab包本身有壓縮功能迁筛,這樣整體的包體也會(huì)減小,如果可能,可以把a(bǔ)b包全部或部分放服務(wù)器耕挨,第一次運(yùn)行游戲的時(shí)候再下載细卧,比如《王者榮耀》,這樣來節(jié)省包體體積筒占。
(2): 骨骼動(dòng)畫優(yōu)化:
3D游戲中骨骼動(dòng)畫也是非常消耗性能的地方贪庙,因?yàn)槊繋?我們都要通過動(dòng)畫組件采樣,采樣后重新計(jì)算出來我們的頂點(diǎn)的位置翰苫,傳給GPU的渲染管線來處理繪制, 我們可以將骨骼動(dòng)畫的每幀頂點(diǎn)的位置緩存到一個(gè)紋理貼圖里面止邮,用空間換時(shí)間的方式來節(jié)約動(dòng)畫組件的開銷这橙,并嘗試合并Drawcall。
(3): LOD的優(yōu)化:
對(duì)于大規(guī)模多角色的場(chǎng)景游戲导披,我們要開啟LOD屈扎,讓遠(yuǎn)處的物體用盡量少的面,近處的物體用更多的面, 來提升我們運(yùn)行時(shí)候的性能撩匕。
(4): 使用3D模型細(xì)節(jié)增強(qiáng),提升計(jì)算性能:
使用法線貼圖鹰晨,高度貼圖等細(xì)節(jié)增強(qiáng)手段來降低模型的面數(shù)同時(shí),能獲得和高模同樣的細(xì)節(jié)和更好的計(jì)算性能止毕。
(5): 光照優(yōu)化:
靜態(tài)光照烘培+反射探頭來做更好的場(chǎng)景效果模蜡,代替實(shí)時(shí)的光照計(jì)算,減少光源的數(shù)目扁凛。對(duì)于一些物體的發(fā)光特效哩牍,可以通過shader來實(shí)現(xiàn),而不用加光源令漂。定制Shader,可以將逐像素光照改為逐頂點(diǎn)光照膝昆,節(jié)約逐像素光照的計(jì)算開銷。
6: SetPassCall與Drawcall優(yōu)化
SetPassCall
SetPassCall通俗的講就是更換重新裝載在渲染管線里面的Shader代碼和配置叠必,就像換畫筆一樣的荚孵。SetPassCall開銷非常的大,所以盡可能的要少用一些不同的Shader纬朝,在一個(gè)場(chǎng)景里面收叶。盡可能的讓同一個(gè)Shader 繪制最多的物體后再切換下一個(gè)Shader的物體。盡量避免繪制物體的時(shí)頻繁交叉的來回切換Shader,節(jié)約SetPassCall的次數(shù)共苛。
DrawCall
DrawCall 優(yōu)化,其實(shí)很簡單, 三種優(yōu)化手段判没,靜態(tài)合批,動(dòng)態(tài)合批隅茎,GPU Instancing合批, 然后我們針對(duì)合批的條件去達(dá)成對(duì)應(yīng)的條件就可以了澄峰,比如,我們做一個(gè)捕魚達(dá)人3D游戲辟犀,我們有很多的魚俏竞,可以把魚的所有紋理貼圖,放到一個(gè)大圖里面堂竟,這樣魂毁,這些魚就是同樣的Shader,同樣的紋理貼圖對(duì)象,就可以達(dá)到合批的條件而做到合批, 節(jié)約Drawcall出嘹。
(7): 物理引擎的優(yōu)化:
能不用物理引擎的游戲席楚,盡量不用物理引擎,能自己實(shí)現(xiàn)的盡量用代碼自己實(shí)現(xiàn)税稼,因?yàn)槲锢硪娴拈_銷畢竟擺在那里了, 物理引擎使用很簡單烦秩,但是性能開銷也不可忽視刁赦。有一些不是真正的物理游戲,比如Moba類的游戲闻镶,防止物體穿透等甚脉,其實(shí)我們可以不用物理引擎,通過制作地圖格子的方式铆农,標(biāo)記障礙物牺氨,自己控制的時(shí)候,如果進(jìn)入障礙物的標(biāo)記墩剖,就不讓它更新位置即可,這些可以替換物理引擎獲得很好的性能效果猴凹。常用的有菱形的地圖格子與六邊形的地圖格子。
暫時(shí)不用的剛體岭皂,或者不在視線范圍內(nèi)的剛體可以根據(jù)游戲的需要郊霎,顯示和隱藏,達(dá)到節(jié)約物理引擎計(jì)算的目的爷绘。修改物理引擎全局的迭代參數(shù)书劝,獲得實(shí)用性的同時(shí)又有更好的性能。了解物理碰撞器的性能開銷土至,球體碰撞器最小购对,網(wǎng)格碰撞器最大,盡量使用開銷小的碰撞器, 對(duì)于靜態(tài)物體陶因,能夠合并物理碰撞器的盡量用一個(gè)物理碰撞器骡苞。
(8): 陰影的優(yōu)化:
通過開關(guān)控制陰影,在低端機(jī)上關(guān)閉陰影獲得更好的運(yùn)行幀率楷扬,在高端機(jī)上開啟陰影,獲得更好的運(yùn)行效果解幽。通過偽陰影技術(shù)來做貼圖,節(jié)約陰影計(jì)算的開銷, 可以自己定制Shader來實(shí)現(xiàn)高性能的陰影效果烘苹。
(9): Shader優(yōu)化:
減少Shader中的條件判斷和展開循環(huán)躲株,來獲得更好的指令緩沖cache 命中率, 減少一些復(fù)雜的計(jì)算,可以采用一些空間換時(shí)間的方法來緩存計(jì)算結(jié)果螟加。逐頂點(diǎn)計(jì)算來替代逐片元的計(jì)算徘溢,減少計(jì)算次數(shù)吞琐±μ剑可以把Shader 設(shè)置為常駐內(nèi)存緩存,這樣節(jié)約SetPassCall所帶來的開銷站粟。
10: C#良好編碼習(xí)慣與算法思想
Update里面盡量不要使用GetComponent, Find等黍图,可以在初始化的時(shí)候先找出來,能放Update里, 盡量不放FixedUpdate, 這樣低端機(jī)上能節(jié)約計(jì)算次數(shù)奴烙。全局設(shè)定,降低FixedUpdate每秒調(diào)用迭代的次數(shù)助被,節(jié)約FixedUpdate迭代時(shí)的計(jì)算時(shí)間剖张。避免大量反復(fù)的new 對(duì)象。一些重復(fù)使用的對(duì)象揩环,可以通過節(jié)點(diǎn)池等先反復(fù)使用搔弄,避免重復(fù)創(chuàng)建與釋放。
可以用多線程來做一些計(jì)算,避免卡住main thread游戲線程導(dǎo)致幀率下降丰滑。不要在游戲主線程里面直接做同步的IO以免卡住游戲線程顾犹,導(dǎo)致幀率下降。
從開始寫代碼起褒墨,要把每行代碼寫好炫刷,長期的堅(jiān)持積累,才能形成良好的代碼習(xí)慣,寫出高性能,高質(zhì)量,高效率的代碼郁妈,學(xué)好數(shù)據(jù)結(jié)構(gòu)與算法,能很好的分析算法的時(shí)間復(fù)雜度浑玛,空間復(fù)雜度等。
經(jīng)過上面的一些討論噩咪,可能還會(huì)有很多優(yōu)化技巧顾彰,歡迎大家留言討論。同時(shí)我們有很多免費(fèi)的Unity 性能優(yōu)化的視頻課程胃碾,供大家可以學(xué)習(xí)拘央,成為優(yōu)化優(yōu)化的高手,