Unity3D优化
優(yōu)化:
更新不透明貼圖的壓縮格式為ETC 4bit,因?yàn)閍ndroid市場(chǎng)的手機(jī)中的GPU有多種,
每家的GPU支持不同的壓縮格式,但他們都兼容ETC格式,
對(duì)于透明貼圖,我們只能選擇RGBA 16bit 或者RGBA 32bit。
減少FPS,在ProjectSetting-> Quality中的
VSync Count 參數(shù)會(huì)影響你的FPS,EveryVBlank相當(dāng)于FPS=60,EverySecondVBlank = 30;
這兩種情況都不符合游戲的FPS的話,我們需要手動(dòng)調(diào)整FPS,首先關(guān)閉垂直同步這個(gè)功能,然后在代碼的Awake方法里手動(dòng)設(shè)置FPS(Application.targetFrameRate = 45;)
降低FPS的好處:
1)省電,減少手機(jī)發(fā)熱的情況;
2)能都穩(wěn)定游戲FPS,減少出現(xiàn)卡頓的情況。
當(dāng)我們?cè)O(shè)置了FPS后,再調(diào)整下Fixed timestep這個(gè)參數(shù),
這個(gè)參數(shù)在ProjectSetting->Time中,目的是減少物理計(jì)算的次數(shù),來(lái)提高游戲性能。
盡量少使用Update LateUpdate FixedUpdate,這樣也可以提升性能和節(jié)省電量。
多使用事件(不是SendMessage,使用自己寫的,或者C#中的事件委托)。
待機(jī)時(shí),調(diào)整游戲的FPS為1,節(jié)省電量。
圖集大小最好不要高于1024,否則游戲安裝之后、低端機(jī)直接崩潰、原因是手機(jī)系統(tǒng)版本低于2.2、超過(guò)1000的圖集無(wú)法讀取、導(dǎo)致。
2.2 以上沒(méi)有遇見(jiàn)這個(gè)情況。
注意手機(jī)的RAM 與 ROM、小于 512M的手機(jī)、直接放棄機(jī)型適配。
VSCount 垂直同步
unity3d中新建一個(gè)場(chǎng)景空的時(shí)候,幀速率(FPS總是很低),大概在60~70之間。
一直不太明白是怎么回事,現(xiàn)在基本上明白了。我在這里解釋一下原因,如有錯(cuò)誤,歡迎指正。
在Unity3D中當(dāng)運(yùn)行場(chǎng)景打開(kāi)Profiler的時(shí)候,我們會(huì)看到VSync 這一項(xiàng)占了很大的比重。
這個(gè)是什么呢,這個(gè)就是垂直同步,稍后再做解釋。
我們可以關(guān)閉VSync來(lái)提高幀速率,選擇edit->project settings->Quality。
這就關(guān)閉了VSync(垂直同步),現(xiàn)在在運(yùn)行場(chǎng)景看看,幀速率是不是提高很多。
現(xiàn)在來(lái)說(shuō)說(shuō)什么是垂直同步,要知道什么是垂直同步,必須要先明白顯示器的工作原理,
顯示器上的所有圖像都是一線一線的掃描上去的,無(wú)論是隔行掃描還是逐行掃描,
顯示器都有兩種同步參數(shù)——水平同步和垂直同步。
什么叫水平同步?什么叫垂直同步?
垂直和水平是CRT中兩個(gè)基本的同步信號(hào),水平同步信號(hào)決定了CRT畫出一條橫越屏幕線的時(shí)間,
垂直同步信號(hào)決定了CRT從屏幕頂部畫到底部,再返回原始位置的時(shí)間,
而恰恰是垂直同步代表著CRT顯示器的刷新率水平。
為什么關(guān)閉垂直同步信號(hào)會(huì)影響游戲中的FPS數(shù)值?
如果我們選擇等待垂直同步信號(hào)(也就是我們平時(shí)所說(shuō)的垂直同步打開(kāi)),
那么在游戲中或許強(qiáng)勁的顯卡迅速的繪制完一屏的圖像,但是沒(méi)有垂直同步信號(hào)的到達(dá),
顯卡無(wú)法繪制下一屏,只有等85單位的信號(hào)到達(dá),才可以繪制。
這樣FPS自然要受到操作系統(tǒng)刷新率運(yùn)行值的制約。
而如果我們選擇不等待垂直同步信號(hào)(也就是我們平時(shí)所說(shuō)的關(guān)閉垂直同步),那么游戲中作完一屏畫面,
顯卡和顯示器無(wú)需等待垂直同步信號(hào)就可以開(kāi)始下一屏圖像的繪制,自然可以完全發(fā)揮顯卡的實(shí)力。
但是不要忘記,正是因?yàn)榇怪蓖降拇嬖?#xff0c;才能使得游戲進(jìn)程和顯示器刷新率同步,使得畫面更加平滑和穩(wěn)定。
取消了垂直同步信號(hào),固然可以換來(lái)更快的速度,但是在圖像的連續(xù)性上勢(shì)必打折扣。
這也正是很多朋友抱怨關(guān)閉垂直后發(fā)現(xiàn)畫面不連續(xù)的理論原因。
合并材質(zhì)球unity 3d中每倒入一次模型就多一個(gè)材質(zhì)球,可我的這些模型都是共用一張貼圖的就想共用一個(gè)材質(zhì)球,所以每次都要?jiǎng)h除再附上,很麻煩。怎么才能合并這些材質(zhì)球?
采用TexturePacking吧
1、遍歷gameobject,取出material,并根據(jù)shader來(lái)將material分類
2、調(diào)用Unity自帶的PackTextures函數(shù)來(lái)合并每個(gè)shader分類中的material所對(duì)應(yīng)的textures(PackTextures函數(shù)有缺陷,不過(guò)可以將就用)
3、根據(jù)合并的大的texture來(lái)更新原有模型的texture、material已經(jīng)uv坐標(biāo)值。
需要注意的是:需要合并的紋理應(yīng)該是物體在場(chǎng)景中距離相近的,如果物體在場(chǎng)景中的距離較遠(yuǎn),
則不建議合并紋理,因?yàn)檫@樣做很有可能非但起不到優(yōu)化的作用,反而降低了運(yùn)行效率。
mesh合并
分為2種方式合并
1.自帶的合并必須勾選靜態(tài)
2.也可以用腳本來(lái)合并mesh
角色Material數(shù)量
2-3個(gè)
骨骼數(shù)量
小于30個(gè)
面片數(shù)量
300-1500
一般角色應(yīng)該沒(méi)有IK結(jié)點(diǎn)
這是因?yàn)榻巧膭?dòng)作大多數(shù)都是事先設(shè)定好的,并不需要經(jīng)過(guò)IK操作來(lái)進(jìn)行實(shí)時(shí)計(jì)算(Rogdoll除外),所以在模型導(dǎo)入時(shí),不要將IK結(jié)點(diǎn)一起導(dǎo)入。
2、靜態(tài)實(shí)體
不要附加Animation Component
在靜態(tài)實(shí)體上附加Animation部件雖然對(duì)結(jié)果沒(méi)有影響,但卻會(huì)增加一定的CPU開(kāi)銷來(lái)調(diào)用這一組件,所以盡量去掉該組件。
網(wǎng)格頂點(diǎn)數(shù)
小于500
UV值范圍盡量不要超過(guò)(0, 1)區(qū)間
盡量保證UV值不越界,這對(duì)于將來(lái)的紋理拼合優(yōu)化很有幫助。
3、地形
地形的分辨率大小
長(zhǎng)寬均盡量小于257。這是因?yàn)榈匦翁?#xff0c;會(huì)造成大量頂點(diǎn)數(shù)據(jù),給你的內(nèi)存帶寬造成一定的影響,在目前的ios設(shè)備中,內(nèi)存帶寬是非常有限的,需要盡量節(jié)省。同時(shí),如果用Unity自帶的地形,一定也要使用Occlusion Culling,因?yàn)閁nity的刷地形工具雖然方便,但卻是framekiller,刷過(guò)之后,你會(huì)發(fā)現(xiàn)drawcall增加的非常多。
混合紋理數(shù)量
不要超過(guò)4。地形的混合操作是很耗時(shí)的,應(yīng)該盡量避免。能合并的紋理盡量合并。
4、紋理
紋理格式
建議png或tga。不用轉(zhuǎn)成ios硬件支持的PVRTC格式,因?yàn)閁nity在發(fā)布時(shí)會(huì)幫你自動(dòng)轉(zhuǎn)的。
紋理尺寸
長(zhǎng)寬小于1024。同時(shí)應(yīng)該盡可能地小,夠用就好,以保證紋理對(duì)內(nèi)存帶寬的影響達(dá)到最小。
支持Mipmap
建議生成Mipmap。雖然這種做法會(huì)增加一些應(yīng)用程序的大小,但在游戲運(yùn)行時(shí),系統(tǒng)會(huì)根據(jù)需求應(yīng)用Mipmap來(lái)渲染,從而減少內(nèi)存帶寬。
檢查Alpha值
如果紋理的alpha通道均為1,則用RGB的24位紋理來(lái)代替RGBA的32位紋理。(據(jù)說(shuō)Unity內(nèi)部會(huì)進(jìn)行自動(dòng)檢測(cè))
5、光源
光源“Important”個(gè)數(shù)
建議1個(gè),一般為方向光。“Important”個(gè)數(shù)應(yīng)該越小越少。個(gè)數(shù)越多,drawcall越多。
Pixel Light數(shù)目
1-2個(gè)。
6、粒子特效
屏幕上的最大粒子數(shù)
建議小于200個(gè)粒子。
每個(gè)粒子發(fā)射器發(fā)射的最大粒子數(shù)
建議不超過(guò)50個(gè)。
粒子大小
如果可以的話,粒子的size應(yīng)該盡可能地小。因?yàn)閁nity的粒子系統(tǒng)的shader無(wú)論是alpha test還是alpha blending都是一筆不小的開(kāi)銷。同時(shí),對(duì)于非常小的粒子,建議粒子紋理去掉alpha通道。
盡量不要開(kāi)啟粒子的碰撞功能。
非常耗時(shí)。
7、音頻
游戲中播放時(shí)間較長(zhǎng)的音樂(lè)(如背景音樂(lè))
使用.ogg或.mp3的壓縮格式。
較短音樂(lè)(如槍聲)
使用.wav和.aif的未壓縮音頻格式。
8、相機(jī)
裁剪平面
將遠(yuǎn)平面設(shè)置成合適的距離。遠(yuǎn)平面過(guò)大會(huì)將一些不必要的物體加入渲染,降低效率。
根據(jù)不同的物體設(shè)置不同的遠(yuǎn)裁剪平面
Unity提供了可以根據(jù)不同的layer來(lái)設(shè)置不同的view distance,所以我們可以實(shí)現(xiàn)將物體進(jìn)行分層,大物體層設(shè)置的可視距離大些,而小物體層可以設(shè)置地小些,另外,一些開(kāi)銷比較大的實(shí)體(如粒子系統(tǒng))可以設(shè)置得更小些等等。
9、碰撞
盡量不用MeshCollider
如果可以的話,盡量不用MeshCollider,以節(jié)省不必要的開(kāi)銷。如果不能避免的話,盡量用減少M(fèi)esh的面片數(shù),或用較少面片的代理體來(lái)代替。
10、其他
Drawcall
盡可能地減少Drawcall的數(shù)量。IOS設(shè)備上建議不超過(guò)100。減少的方法主要有如下幾種:Frustum Culling,Occlusion Culling,Texture Packing。Frustum Culling是Unity內(nèi)建的,我們需要做的就是尋求一個(gè)合適的遠(yuǎn)裁剪平面;Occlusion Culling,遮擋剔除,Unity內(nèi)嵌了Umbra,一個(gè)非常好OC庫(kù)。但Occlusion Culling也并不是放之四海而皆準(zhǔn)的,有時(shí)候進(jìn)行OC反而比不進(jìn)行還要慢,建議在OC之前先確定自己的場(chǎng)景是否適合利用OC來(lái)優(yōu)化;Texture Packing,或者叫Texture Atlasing,是將同種shader的紋理進(jìn)行拼合,根據(jù)Unity的static batching的特性來(lái)減少draw call。建議使用,但也有弊端,那就是一定要將場(chǎng)景中距離相近的實(shí)體紋理進(jìn)行拼合,否則,拼合后很可能會(huì)增加每幀渲染所需的紋理大小,加大內(nèi)存帶寬的負(fù)擔(dān)。這也就是為什么會(huì)出現(xiàn)“DrawCall降了,渲染速度也變慢了”的原因。
非運(yùn)動(dòng)物體盡量打上Static標(biāo)簽
Unity在運(yùn)行時(shí)會(huì)對(duì)static物體進(jìn)行自動(dòng)優(yōu)化處理,所以應(yīng)該盡可能將非運(yùn)行實(shí)體勾上static標(biāo)簽。
場(chǎng)景中盡可能地使用prefab
盡可能地使用prefab的實(shí)例化物體,以降低內(nèi)存帶寬的負(fù)擔(dān)。檢查實(shí)體的PrefabType,盡量將其變成PrefabInstance,而不是ModelPrefabInstance。
移動(dòng)平臺(tái)相對(duì)于PC機(jī),具有體積小,計(jì)算弱,帶寬少的特點(diǎn)。
因此做手機(jī)游戲的開(kāi)發(fā),優(yōu)化的方向,與力度對(duì)比PC游戲都有所區(qū)別。
必須要做到優(yōu)化流程,合理利用資源。
目前在手機(jī)上面,還不能夠像PC游戲那樣追求高質(zhì)量渲染效果,為了讓手機(jī)不那么容易發(fā)燙,還要控制cpu,gpu,不能讓他們?nèi)龠\(yùn)算。
材質(zhì)方面:
紋理方面,建議使用壓縮紋理,
Android上面使用ETC1,蘋果上面使用PVRTC。
UV坐標(biāo)控制在0到1之間,人物模型面數(shù)控制在1500內(nèi),骨骼控制在30個(gè)以內(nèi)。
場(chǎng)景中使用一個(gè)主光(不能再多了)。
盡量減少alphaTest和alphaBlend材質(zhì)的使用。在手機(jī)上,這是很殺效率的。
骨骼動(dòng)畫方面:
在動(dòng)畫方面可以考慮不使用插值,固定的幀率的動(dòng)畫。
如果要做插值,考慮使用四元數(shù)(表示旋轉(zhuǎn))和向量(表示位移)來(lái)做插值。
四元數(shù)做插值速度比矩陣來(lái)的快,Slerp提供了平滑插值。
化的常規(guī)技巧
剖析你的游戲。
不要花費(fèi)時(shí)間來(lái)優(yōu)化那些晦澀的代碼或者縮減圖形文件的大小,除非這是你游戲的瓶頸。
第一次剖析你的游戲?qū)?huì)使你發(fā)現(xiàn)你游戲的瓶頸。Apple’s Shark是一個(gè)很好的用來(lái)剖析基于OpenGL的程序的工具。
再次剖析你的游戲。
優(yōu)化之后不要忘記再剖析一次你的游戲,這樣可以檢查你所做的優(yōu)化是否達(dá)到了預(yù)期的效果。
當(dāng)然,這樣做也可能會(huì)使你發(fā)現(xiàn)更多的瓶頸。
流程第一、性能第二。花費(fèi)時(shí)間來(lái)使你游戲的創(chuàng)建盡可能地流暢。
盡可能快地修正游戲中的錯(cuò)誤將會(huì)使你后期更容易優(yōu)化你的游戲。
在Scene View中測(cè)試場(chǎng)景。
這樣做將會(huì)使你清楚了解這個(gè)場(chǎng)景中的物體或者附加在物體上的腳本是否降低了游戲性能。
如果Scene View反應(yīng)遲鈍,那么有可能是圖形方面的原因,如果Scene View反應(yīng)不遲鈍,那么瓶頸可能出在腳本或者物理系統(tǒng)上。
禁用指定游戲物體。
在play模式下,嘗試禁用并啟用游戲物體來(lái)排查出游戲慢的原因。
網(wǎng)格
如果可能的話,把相鄰的物體(網(wǎng)格)合并為一個(gè)只有一個(gè)材質(zhì)的物體(網(wǎng)格)。比如,你的游戲中包含一個(gè)桌子,上面有一堆東西,你完全可以在3D程序中將它們合并在一起(這可能也需要你將這些物體的紋理合并為一個(gè)大的紋理集)。減少需要渲染的物體的數(shù)量可以極大地提高游戲性能。
不要有不必要的網(wǎng)格。
如果你的游戲場(chǎng)景中有一個(gè)人物,那么他應(yīng)該是一個(gè)網(wǎng)格。如果你有一個(gè)船,那么它也應(yīng)該只是一個(gè)網(wǎng)格。
每一個(gè)網(wǎng)格只用一種材質(zhì)。
使用極少的面數(shù)的網(wǎng)格(比如500個(gè)多邊形以下)。
最好把你人物的三角面數(shù)量控制在1500-2000個(gè)之間。
這個(gè)數(shù)量可以說(shuō)是游戲質(zhì)量和性能之間一個(gè)均衡值。如果你的模型有四邊形,那么在導(dǎo)入模型的時(shí)候,引擎將會(huì)把每個(gè)四邊形變?yōu)閮蓚€(gè)三角形。
光照
像素光。
像素光可以讓你的游戲看起來(lái)效果很牛逼,但是不要使用過(guò)多的像素光。
在你的游戲中可以使用質(zhì)量管理器來(lái)調(diào)節(jié)像素光的數(shù)量來(lái)取得一個(gè)性能和質(zhì)量的均衡點(diǎn).
性能占用順序:聚光燈>點(diǎn)光源>平行光。
一個(gè)好的點(diǎn)亮場(chǎng)景的方法就是先得到你想要的效果,然后看看哪些光更重要;
在保持光效的前提下看看哪些光可以去掉。
點(diǎn)光源和聚光燈只影響它們范圍內(nèi)的網(wǎng)格。
如果一個(gè)網(wǎng)格處于點(diǎn)光源或者聚光燈的照射范圍之外,并且光源的attenuate開(kāi)關(guān)是打開(kāi)的,那么這個(gè)網(wǎng)格將不會(huì)被光源所影響,這樣就可以節(jié)省性能開(kāi)銷。
這樣做理論上來(lái)講可以使用很多小的點(diǎn)光源而且依然能有一個(gè)好的性能,因?yàn)檫@些光源只影響一小部分物體。
一個(gè)網(wǎng)格在有8個(gè)以上光源影響的時(shí)候,只響應(yīng)前8個(gè)最亮的光源。
貼圖
在外觀不變的前提下,貼圖大小越小越好。
如果你的顯卡的顯存不夠大的話,你游戲中的貼圖將會(huì)被轉(zhuǎn)存到系統(tǒng)內(nèi)存中,在顯卡調(diào)用它們的時(shí)候再傳到顯卡中。
對(duì)于比較新的電腦來(lái)說(shuō),內(nèi)存和顯卡之間有足夠的帶寬來(lái)達(dá)到一個(gè)很好的性能;
如果你很無(wú)恥地用了巨多的大圖片的話,在低顯存的電腦上運(yùn)行你的游戲的時(shí)候,你的游戲必然會(huì)掛掉。
倒是沒(méi)有必要在圖形編輯軟件中調(diào)整貼圖的大小。你可以在unity導(dǎo)入貼圖的時(shí)候進(jìn)行調(diào)整。
不要使用低質(zhì)量的圖片。
在小播放界面的游戲中使用低質(zhì)量的jpeg圖片或者低色彩的png圖片亦或是gif圖片沒(méi)什么問(wèn)題。
在發(fā)布游戲的時(shí)候,引擎會(huì)自動(dòng)壓縮這些圖片,多重壓縮和解壓將會(huì)降低圖片的質(zhì)量,所以最好保持貼圖文件的分辨率為原始分辨率。
這樣就會(huì)減少多重壓縮和解壓所導(dǎo)致的圖片失真現(xiàn)象。
Shaders
多重效果的shader就比看起來(lái)樣式很單一的shader要更耗費(fèi)資源。
同樣在一個(gè)擁有貼圖和光反射的物體上,使用VertexLit Diffuse shader無(wú)疑是最省資源的。
在美術(shù)制作場(chǎng)景的過(guò)程中,會(huì)使用到大量的粒子系統(tǒng)。
比如場(chǎng)景中的火把。在我們的一個(gè)地下城場(chǎng)景中,美術(shù)們放置了大量的火把。整個(gè)場(chǎng)景中的各個(gè)地方,有100來(lái)個(gè)火把。
unity中,在攝像機(jī)范圍外的粒子系統(tǒng)雖然不會(huì)被繪制。
但是update是一直持續(xù)的。這也就意味著,這100多個(gè)火把,不論是否可見(jiàn)都在更新。
這個(gè)設(shè)計(jì)應(yīng)該是很不合理的,在我看過(guò)的其他引擎中,都會(huì)有一個(gè)開(kāi)關(guān),來(lái)控制不可見(jiàn)的粒子系統(tǒng)是否需要update。
有的粒子系統(tǒng)在不可見(jiàn)的時(shí)候需要更新,比如爆炸。有的不需要更新,比如火堆火把。
為了避免不必要的update開(kāi)銷,尤其是最后游戲是要發(fā)布到頁(yè)游平臺(tái)(web player只能使用一個(gè)cpu的核)。
于是寫了一個(gè)腳本,控制不可見(jiàn)的粒子系統(tǒng)就不更新。
該腳本主要是用到了2個(gè)MonoBehaviour的函數(shù)。
OnBecameInvisible() 當(dāng)變?yōu)椴豢梢?jiàn) 和 OnBecameVisible() 當(dāng)變成可見(jiàn)。
要這2個(gè)函數(shù)起作用的前提是,該GameObject綁定了MeshRender組件。
所以,我們要在粒子系統(tǒng)的GameObject放置在一個(gè)GameObject 下,且給該GameObject綁定一個(gè)MeshRender 與 MeshFilter。
MeshFilter中的mesh可以隨便找個(gè)cube。
在Start() 的時(shí)候,把最GameObject的scale設(shè)置為很小,以保證該cube不被看見(jiàn)。
其實(shí)遍歷所有的child,把a(bǔ)ctive設(shè)置為false。
在OnBecameVisible 中 遍歷所有child,把a(bǔ)ctive設(shè)置為true。
在OnBecameInvisible中 遍歷所有child,把a(bǔ)ctive設(shè)置為false。
Unity(或者說(shuō)基本所有圖形引擎)生成一幀畫面的處理過(guò)程大致可以這樣簡(jiǎn)化描述:引擎首先經(jīng)過(guò)簡(jiǎn)單的可見(jiàn)性測(cè)試,確定攝像機(jī)可以看到的物體,然后把這些物體的頂點(diǎn)(包括本地位置、法線、UV等),索引(頂點(diǎn)如何組成三角形),變換(就是物體的位置、旋轉(zhuǎn)、縮放、以及攝像機(jī)位置等),相關(guān)光源,紋理,渲染方式(由材質(zhì)/Shader決定)等數(shù)據(jù)準(zhǔn)備好,然后通知圖形API——或者就簡(jiǎn)單地看作是通知GPU——開(kāi)始繪制,GPU基于這些數(shù)據(jù),經(jīng)過(guò)一系列運(yùn)算,在屏幕上畫出成千上萬(wàn)的三角形,最終構(gòu)成一幅圖像。
在Unity中,每次引擎準(zhǔn)備數(shù)據(jù)并通知GPU的過(guò)程稱為一次Draw Call。這一過(guò)程是逐個(gè)物體進(jìn)行的,對(duì)于每個(gè)物體,不只GPU的渲染,引擎重新設(shè)置材質(zhì)/Shader也是一項(xiàng)非常耗時(shí)的操作。因此每幀的Draw Call次數(shù)是一項(xiàng)非常重要的性能指標(biāo),對(duì)于iOS來(lái)說(shuō)應(yīng)盡量控制在20次以內(nèi),這個(gè)值可以在編輯器的Statistic窗口看到。
Unity內(nèi)置了Draw Call Batching技術(shù),從名字就可以看出,它的主要目標(biāo)就是在一次Draw Call中批量處理多個(gè)物體。只要物體的變換和材質(zhì)相同,GPU就可以按完全相同的方式進(jìn)行處理,即可以把它們放在一個(gè)Draw Call中。Draw Call Batching技術(shù)的核心就是在可見(jiàn)性測(cè)試之后,檢查所有要繪制的物體的材質(zhì),把相同材質(zhì)的分為一組(一個(gè)Batch),然后把它們組合成一個(gè)物體(統(tǒng)一變換),這樣就可以在一個(gè)Draw Call中處理多個(gè)物體了(實(shí)際上是組合后的一個(gè)物體)。
但Draw Call Batching存在一個(gè)缺陷,就是它需要把一個(gè)Batch中的所有物體組合到一起,相當(dāng)于創(chuàng)建了一個(gè)與這些物體加起來(lái)一樣大的物體,與此同時(shí)就需要分配相應(yīng)大小的內(nèi)存。這不僅會(huì)消耗更多內(nèi)存,還需要消耗CPU時(shí)間。特別是對(duì)于移動(dòng)的物體,每一幀都得重新進(jìn)行組合,這就需要進(jìn)行一些權(quán)衡,否則得不償失。但對(duì)于靜止不動(dòng)的物體來(lái)說(shuō),只需要進(jìn)行一次組合,之后就可以一直使用,效率要高得多。
Unity提供了Dynamic Batching和Static Batching兩種方式。Dynamic Batching是完全自動(dòng)進(jìn)行的,不需要也無(wú)法進(jìn)行任何干預(yù),對(duì)于頂點(diǎn)數(shù)在300以內(nèi)的可移動(dòng)物體,只要使用相同的材質(zhì),就會(huì)組成Batch。Static Batching則需要把靜止的物體標(biāo)記為Static,然后無(wú)論大小,都會(huì)組成Batch。如前文所說(shuō),Static Batching顯然比Dynamic Batching要高效得多,于是,Static Batching功能是收費(fèi)的……
要有效利用Draw Call Batching,首先是盡量減少場(chǎng)景中使用的材質(zhì)數(shù)量,即盡量共享材質(zhì),對(duì)于僅紋理不同的材質(zhì)可以把紋理組合到一張更大的紋理中(稱為Texture Atlasing)。然后是把不會(huì)移動(dòng)的物體標(biāo)記為Static。此外還可以通過(guò)CombineChildren腳本(Standard Assets/Scripts/Unity Scripts/CombineChildren)手動(dòng)把物體組合在一起,但這個(gè)腳本會(huì)影響可見(jiàn)性測(cè)試,因?yàn)榻M合在一起的物體始終會(huì)被看作一個(gè)物體,從而會(huì)增加GPU要處理的幾何體數(shù)量,因此要小心使用。
對(duì)于復(fù)雜的靜態(tài)場(chǎng)景,還可以考慮自行設(shè)計(jì)遮擋剔除算法,減少可見(jiàn)的物體數(shù)量同時(shí)也可以減少Draw Call。
總之,理解Draw Call和Draw Call Batching原理,根據(jù)場(chǎng)景特點(diǎn)設(shè)計(jì)相應(yīng)的方案來(lái)盡量減少Draw Call次數(shù)才是王道,其它方面亦然。
Draw Call Batching (繪制調(diào)用批處理)
To draw an object on the screen, the engine has to issue a draw call to the graphics API (OpenGL ES in the case of iOS). Every single draw call requires a significant amount of work on the part of the graphics API, causing significant performance overhead on the CPU side.
在屏幕上渲染物體,引擎需要發(fā)出一個(gè)繪制調(diào)用來(lái)訪問(wèn)圖形API(iOS系統(tǒng)中為OpenGL ES)。
每個(gè)繪制調(diào)用需要進(jìn)行大量的工作來(lái)訪問(wèn)圖形API,從而導(dǎo)致了CPU方面顯著的性能開(kāi)銷。
Unity combines a number of objects at runtime and draws them together with a single draw call. This operation is called “batching”. The more objects Unity can batch together, the better rendering performance you will get.
Unity在運(yùn)行時(shí)可以將一些物體進(jìn)行合并,從而用一個(gè)繪制調(diào)用來(lái)渲染他們。這一操作,我們稱之為“批處理”。
一般來(lái)說(shuō),Unity批處理的物體越多,你就會(huì)得到越好的渲染性能。
Built-in batching support in Unity has significant benefit over simply combining geometry in the modeling tool (or using theCombineChildren script from the Standard Assets package). Batching in Unity happensafter visibility determination step. The engine does culling on each object individually, and the amount of rendered geometry is going to be the same as without batching. Combining geometry in the modeling tool, on the other hand, prevents effecient culling and results in much higher amount of geometry being rendered.
Unity中內(nèi)建的批處理機(jī)制所達(dá)到的效果要明顯強(qiáng)于使用幾何建模工具(或使用Standard Assets包中的CombineChildren腳本)的批處理效果。
這是因?yàn)?#xff0c;Unity引擎的批處理操作是在物體的可視裁剪操作之后進(jìn)行的。
Unity先對(duì)每個(gè)物體進(jìn)行裁剪,然后再進(jìn)行批處理,這樣可以使渲染的幾何總量在批處理前后保持不變。
但是,使用幾何建模工具來(lái)拼合物體,會(huì)妨礙引擎對(duì)其進(jìn)行有效的裁剪操作,從而導(dǎo)致引擎需要渲染更多的幾何面片。
Materials
材質(zhì)
Only objects sharing the same material can be batched together. Therefore, if you want to achieve good batching, you need to share as many materials among different objects as possible.
只有擁有相同材質(zhì)的物體才可以進(jìn)行批處理。
因此,如果你想要得到良好的批處理效果,你需要在程序中盡可能地復(fù)用材質(zhì)和物體。
If you have two identical materials which differ only in textures, you can combine those textures into a single big texture - a process often calledtexture atlasing. Once textures are in the same atlas, you can use single material instead.
如果你的兩個(gè)材質(zhì)僅僅是紋理不同,那么你可以通過(guò) 紋理拼合 操作來(lái)將這兩張紋理拼合成一張大的紋理。
一旦紋理拼合在一起,你就可以使用這個(gè)單一材質(zhì)來(lái)替代之前的兩個(gè)材質(zhì)了。
If you need to access shared material properties from the scripts, then it is important to note that modifyingRenderer.material will create a copy of the material. Instead, you should useRenderer.sharedMaterial to keep material shared.
如果你需要通過(guò)腳本來(lái)訪問(wèn)復(fù)用材質(zhì)屬性,那么值得注意的是改變Renderer.material將會(huì)造成一份材質(zhì)的拷貝。
因此,你應(yīng)該使用Renderer.sharedMaterial來(lái)保證材質(zhì)的共享狀態(tài)。
Dynamic Batching
動(dòng)態(tài)批處理
Unity can automatically batch moving objects into the same draw call if they share the same material.
如果動(dòng)態(tài)物體共用著相同的材質(zhì),那么Unity會(huì)自動(dòng)對(duì)這些物體進(jìn)行批處理。
Dynamic batching is done automatically and does not require any additional effort on your side.
動(dòng)態(tài)批處理操作是自動(dòng)完成的,并不需要你進(jìn)行額外的操作。
Tips:
提醒:
1、 Batching dynamic objects has certain overheadper vertex, so batching is applied only to meshes containing less than900 vertex attributes in total.
批處理動(dòng)態(tài)物體需要在每個(gè)頂點(diǎn)上進(jìn)行一定的開(kāi)銷,所以動(dòng)態(tài)批處理僅支持小于900頂點(diǎn)的網(wǎng)格物體。
2、 If your shader is using Vertex Position, Normal and single UV, then you can batch up to 300 verts and if your shader is using Vertex Position, Normal, UV0, UV1 and
Tangent, then only 180 verts.
Please note: attribute count limit might be changed in future
如果你的著色器使用頂點(diǎn)位置,法線和UV值三種屬性,那么你只能批處理300頂點(diǎn)以下的物體;
如果你的著色器需要使用頂點(diǎn)位置,法線,UV0,UV1和切向量,那你只
能批處理180頂點(diǎn)以下的物體。
請(qǐng)注意:屬性數(shù)量的限制可能會(huì)在將來(lái)進(jìn)行改變。
4、 Don’t use scale. Objects with scale (1,1,1) and (2,2,2) won’t batch.
不要使用縮放尺度(scale)。分別擁有縮放尺度(1,1,1)和(2,2,2)的兩個(gè)物體將不會(huì)進(jìn)行批處理。
5、 Uniformly scaled objects won’t be batched with non-uniformly scaled ones.
統(tǒng)一縮放尺度的物體不會(huì)與非統(tǒng)一縮放尺度的物體進(jìn)行批處理。
Objects with scale (1,1,1) and (1,2,1) won’t be batched. On the other hand (1,2,1) and (1,3,1) will be.
使用縮放尺度(1,1,1)和 (1,2,1)的兩個(gè)物體將不會(huì)進(jìn)行批處理,但是使用縮放尺度(1,2,1)和(1,3,1)的兩個(gè)物體將可以進(jìn)行批處理。
6、 Using different material instances will cause batching to fail.
使用不同材質(zhì)的實(shí)例化物體(instance)將會(huì)導(dǎo)致批處理失敗。
7、 Objects with lightmaps have additional (hidden) material parameter: offset/scale in lightmap, so lightmapped objects won’t be batched (unless they point to same
portions of lightmap)
擁有l(wèi)ightmap的物體含有額外(隱藏)的材質(zhì)屬性,比如:lightmap的偏移和縮放系數(shù)等。所以,擁有l(wèi)ightmap的物體將不會(huì)進(jìn)行批處理(除非他們指向lightmap的同一
部分)。
8、 Multi-pass shaders will break batching. E.g. Almost all unity shaders supports several lights in forward rendering, effectively doing additional pass for them
多通道的shader會(huì)妨礙批處理操作。比如,幾乎unity中所有的著色器在前向渲染中都支持多個(gè)光源,并為它們有效地開(kāi)辟多個(gè)通道。
9、 Using instances of a prefab automatically are using the same mesh and material.
預(yù)設(shè)體的實(shí)例會(huì)自動(dòng)地使用相同的網(wǎng)格模型和材質(zhì)。
Static Batching
靜態(tài)批處理
Static batching, on the other hand, allows the engine to reduce draw calls for geometry of any size (provided it does not move and shares the same material). Static batching is significantly more efficient than dynamic batching. You should choose static batching as it will require less CPU power.
相對(duì)而言,靜態(tài)批處理操作允許引擎對(duì)任意大小的幾何物體進(jìn)行批處理操作來(lái)降低繪制調(diào)用(只要這些物體不移動(dòng),并且擁有相同的材質(zhì))。因此,靜態(tài)批處理比動(dòng)態(tài)批處理更加有效,你應(yīng)該盡量低使用它,因?yàn)樗枰俚腃PU開(kāi)銷。
In order to take advantage of static batching, you need explicitly specify that certain objects are static and willnot move, rotate or scale in the game. To do so, you can mark objects as static using the Static checkbox in the Inspector:
為了更好地使用靜態(tài)批處理,你需要明確指出哪些物體是靜止的,并且在游戲中永遠(yuǎn)不會(huì)移動(dòng)、旋轉(zhuǎn)和縮放。想完成這一步,你只需要在檢測(cè)器(Inspector)中將Static復(fù)選框打勾即可,如下圖所示:
Using static batching will require additional memory for storing the combined geometry. If several objects shared the same geometry before static batching, then a copy of geometry will be created for each object, either in the Editor or at runtime. This might not always be a good idea - sometimes you will have to sacrifice rendering performance by avoiding static batching for some objects to keep a smaller memory footprint. For example, marking trees as static in a dense forest level can have serious memory impact.
使用靜態(tài)批處理操作需要額外的內(nèi)存開(kāi)銷來(lái)儲(chǔ)存合并后的幾何數(shù)據(jù)。在靜態(tài)批處理之前,如果一些物體共用了同樣的幾何數(shù)據(jù),那么引擎會(huì)在編輯以及運(yùn)行狀態(tài)對(duì)每個(gè)物體創(chuàng)建一個(gè)幾何數(shù)據(jù)的備份。這并不總是一個(gè)好的想法,因?yàn)橛袝r(shí)候,你將不得不犧牲一點(diǎn)渲染性能來(lái)防止一些物體的靜態(tài)批處理,從而保持較少的內(nèi)存開(kāi)銷。比如,將濃密森里中樹(shù)設(shè)為Static,會(huì)導(dǎo)致嚴(yán)重的內(nèi)存開(kāi)銷。
Static batching is only available in Unity iOS Advanced.
靜態(tài)批處理目前只支持Unity iOS Advanced。
備注:最近一直在研究Unity3D的性能優(yōu)化問(wèn)題,這段時(shí)間可能會(huì)多翻譯這方面的文章。
前兩天,MadFinger,就是當(dāng)今iOS與Android上畫質(zhì)最牛逼閃閃的游戲之一——ShadowGun的開(kāi)發(fā)商,令人驚異地放出了一個(gè)ShadowGun的樣例關(guān)卡以及若干可免費(fèi)使用的Shader,國(guó)外同行們的分享精神真的是令人贊嘆不已。原文在這里,以下是我的一些摘錄和筆記。
首先是一些優(yōu)化常識(shí)。針對(duì)圖形方面的優(yōu)化主要包括三角形數(shù)量,紋理所占內(nèi)存,以及Shader,前兩項(xiàng)基本沒(méi)什么好講的,針對(duì)設(shè)備機(jī)能的限制制定相應(yīng)的指標(biāo)即可,所以Shader就成為了圖形性能優(yōu)化的關(guān)鍵。
Alpha blending
在Unity官方文檔中講,由于硬件原因,在iOS設(shè)備上使用alpha-test會(huì)造成很大的性能開(kāi)銷,應(yīng)盡量使用alpha-blend代替。這里提到,在同屏使用alpha-blend的面數(shù),尤其是這些面所占屏幕面積的大小,對(duì)性能也會(huì)造成很大影響。原因是使用alpha-blend的面會(huì)造成overdraw的增加,這尤其對(duì)低性能設(shè)備的影響很大。不過(guò)沒(méi)有購(gòu)買Pro版,沒(méi)有Occlusion Culling功能的話,就不必顧慮這一問(wèn)題了,反正overdraw是必然的。
復(fù)雜的Per-pixel shader
Per-pixel shader即Fragment shader,顧名思義是要對(duì)每個(gè)渲染到屏幕上的像素做處理的shader,如果per-pixel shader比較復(fù)雜且需要處理的像素很多時(shí),也就是使用該shader的面占屏幕面積很大時(shí),對(duì)性能的影響甚至要超過(guò)alpha blending。因此復(fù)雜的per-pixel shader只適用于小物體。
下面是對(duì)幾個(gè)Shader的逐一講解:
Environment specular maps(Shader Virtual Gloss Per Vertex Additive)
Specular map通常都是利用貼圖的alpha通道來(lái)定義物體表面的光滑程度(反光度),這個(gè)shader的特點(diǎn)是per-vertex計(jì)算反光度的,有著相當(dāng)不錯(cuò)的效果的同時(shí)比per-pixel的shader性能要高得多。這個(gè)shader很適用于關(guān)卡環(huán)境等占很大區(qū)域的模型。
經(jīng)過(guò)優(yōu)化的動(dòng)態(tài)角色光照和陰影(Light probes和BRDF Shader)
傳統(tǒng)的Lightmaps無(wú)法支持動(dòng)態(tài)物體,對(duì)此Unity提供了Light probes技術(shù),預(yù)先把動(dòng)態(tài)物體的光照信息保存在代理對(duì)象(即Light probes)中,運(yùn)行時(shí)動(dòng)態(tài)物體從距離最近的Probe中獲取光照信息。
Unity本身還提供了一個(gè)效果非常棒的專為移動(dòng)設(shè)備優(yōu)化過(guò)的角色Shader,支持Diffuse、Specular和Normal maps,并通過(guò)一個(gè)特殊的腳本生成貼圖用于模仿BRDF光照效果。最終產(chǎn)生的效果堪比次時(shí)代大作中的角色光影效果。
霧和體積光(Shader Blinking Godrays)
目前在移動(dòng)設(shè)備上要開(kāi)啟真正的霧效基本不可行,ShadowGun的方案是通過(guò)簡(jiǎn)單的網(wǎng)格+透明貼圖(稱為霧面)來(lái)模擬霧效。在玩家靠近時(shí),霧面逐漸變淡,同時(shí)fog plane的頂點(diǎn)也會(huì)移開(kāi)(即使完全透明的alpha面也會(huì)消耗很多渲染時(shí)間)。
使用這個(gè)Shader的網(wǎng)格需要經(jīng)過(guò)處理:
頂點(diǎn)的alpha值用于決定頂點(diǎn)是否可以移動(dòng)(在例子中0為不可動(dòng),1為可動(dòng))。
頂點(diǎn)法線決定移動(dòng)的方向
然后Shader通過(guò)計(jì)算與觀察者的距離來(lái)控制霧面的淡入/淡出。
這個(gè)Shader還可以用來(lái)做體積光和其它一些alpha效果。
飛機(jī)墜毀的濃煙效果(Shader Scroll 2 Layers Sine Alpha-blended)
通過(guò)粒子產(chǎn)生濃煙的代價(jià)太高,所以ShadowGun中使用了網(wǎng)格+貼圖動(dòng)畫來(lái)制作這個(gè)效果。通過(guò)混合兩層貼圖并讓它們交錯(cuò)移動(dòng)來(lái)產(chǎn)生動(dòng)畫效果。其中頂點(diǎn)alpha值用于讓網(wǎng)格的邊緣看起來(lái)比較柔和,同時(shí)使用頂點(diǎn)顏色來(lái)模擬從火焰到煙霧的過(guò)渡效果。
帶動(dòng)態(tài)效果的天空盒(Shader Scroll 2 Layers Multiplicative)
通過(guò)兩張貼圖的混合和移動(dòng)產(chǎn)生云的動(dòng)態(tài)效果。
旗幟和衣服的飄動(dòng)效果(Shader Lightmap + Wind)
同樣利用頂點(diǎn)alpha值決定哪些頂點(diǎn)可以移動(dòng),然后shader的參數(shù)用于調(diào)整擺動(dòng)的方向和速度。
一、程序方面
01、務(wù)必刪除腳本中為空或不需要的默認(rèn)方法;
02、只在一個(gè)腳本中使用OnGUI方法;
03、避免在OnGUI中對(duì)變量、方法進(jìn)行更新、賦值,輸出變量建議在Update內(nèi);
04、同一腳本中頻繁使用的變量建議聲明其為全局變量,腳本之間頻繁調(diào)用的變量或方法建議聲明為全局靜態(tài)變量或方法;
05、不要去頻繁獲取組件,將其聲明為全局變量;
06、數(shù)組、集合類元素優(yōu)先使用Array,其次是List;
07、腳本在不使用時(shí)腳本禁用之,需要時(shí)再啟用;
08、可以使用Ray來(lái)代替OnMouseXXX類方法;
09、需要隱藏/顯示或?qū)嵗瘉?lái)回切換的對(duì)象,盡量不要使用SetActiveRecursively或active,而使用將對(duì)象遠(yuǎn)遠(yuǎn)移出相機(jī)范圍和移回原位的做法;
10、盡量少用模運(yùn)算和除法運(yùn)算,比如a/5f,一定要寫成a*0.2f。
11、對(duì)于不經(jīng)常調(diào)用或更改的變量或方法建議使用Coroutines & Yield;
12、盡量直接聲明腳本變量,而不使用GetComponent來(lái)獲取腳本;
iPhone
13、盡量使用整數(shù)數(shù)字,因?yàn)閕Phone的浮點(diǎn)數(shù)計(jì)算能力很差;
14、不要使用原生的GUI方法;
15、不要實(shí)例化(Instantiate)對(duì)象,事先建好對(duì)象池,并使用Translate“生成”對(duì)象;
二、模型方面
01、合并使用同貼圖的材質(zhì)球,合并使用相同材質(zhì)球的Mesh;
02、角色的貼圖和材質(zhì)球只要一個(gè),若必須多個(gè)則將模型離分離為多個(gè)部分;
02、骨骼系統(tǒng)不要使用太多;
03、當(dāng)使用多角色時(shí),將動(dòng)畫單獨(dú)分離出來(lái);
04、使用層距離來(lái)控制模型的顯示距離;
05、陰影其實(shí)包含兩方面陰暗和影子,建議使用實(shí)時(shí)影子時(shí)把陰暗效果烘焙出來(lái),不要使用燈光來(lái)調(diào)節(jié)光線陰暗。
06、少用像素?zé)艉褪褂孟袼責(zé)舻腟hader;
08、如果硬陰影可以解決問(wèn)題就不要用軟陰影,并且使用不影響效果的低分辨率陰影;
08、實(shí)時(shí)陰影很耗性能,盡量減小產(chǎn)生陰影的距離;
09、允許的話在大場(chǎng)景中使用線性霧,這樣可以使遠(yuǎn)距離對(duì)象或陰影不易察覺(jué),因此可以通過(guò)減小相機(jī)和陰影距離來(lái)提高性能;
10、使用圓滑組來(lái)盡量減少模型的面數(shù);
11、項(xiàng)目中如果沒(méi)有燈光或?qū)ο笤谝苿?dòng)那么就不要使用實(shí)時(shí)燈光;
12、水面、鏡子等實(shí)時(shí)反射/折射的效果單獨(dú)放在Water圖層中,并且根據(jù)其實(shí)時(shí)反射/折射的范圍來(lái)調(diào)整;
13、碰撞對(duì)效率的影響很小,但碰撞還是建議使用Box、Sphere碰撞體;
14、建材質(zhì)球時(shí)盡量考慮使用Substance;
15、盡量將所有的實(shí)時(shí)反射/折射(如水面、鏡子、地板等等)都集合成一個(gè)面;
16、假反射/折射沒(méi)有必要使用過(guò)大分辨率,一般6464就可以,不建議超過(guò)256256;
17、需要更改的材質(zhì)球,建議實(shí)例化一個(gè),而不是使用公共的材質(zhì)球;
18、將不須射線或碰撞事件的對(duì)象置于IgnoreRaycast圖層;
19、將水面或類似效果置于Water圖層
20、將透明通道的對(duì)象置于TransparentFX圖層;
21、養(yǎng)成良好的標(biāo)簽(Tags)、層次(Hieratchy)和圖層(Layer)的條理化習(xí)慣,將不同的對(duì)象置于不同的標(biāo)簽或圖層,三者有效的結(jié)合將很方便的按名稱、類別和屬性來(lái)查找;
22、通過(guò)Stats和Profile查看對(duì)效率影響最大的方面或?qū)ο?#xff0c;或者使用禁用部分模型的方式查看問(wèn)題到底在哪兒;
23、使用遮擋剔除(Occlusion Culling)處理大場(chǎng)景,一種較原生的類LOD技術(shù),并且能夠“分割”作為整體的一個(gè)模型。
三、其它
場(chǎng)景中如果沒(méi)有使用燈光和像素?zé)?#xff0c;就不要使用法線貼圖,因?yàn)榉ň€效果只有在有光源(Direct Light/Point Light/Angle Light/Pixel Light)的情況下才有效果。
四:Profiler內(nèi)存重點(diǎn)關(guān)注優(yōu)化項(xiàng)目
1)ManagedHeap.UsedSize: 移動(dòng)游戲建議不要超過(guò)20MB.
2)SerializedFile: 通過(guò)異步加載(LoadFromCache、WWW等)的時(shí)候留下的序列化文件,可監(jiān)視是否被卸載.
3)WebStream: 通過(guò)異步WWW下載的資源文件在內(nèi)存中的解壓版本,比SerializedFile大幾倍或幾十倍,不過(guò)我們現(xiàn)在項(xiàng)目中展示沒(méi)有。
4)Texture2D: 重點(diǎn)檢查是否有重復(fù)資源和超大Memory是否需要壓縮等.
5)AnimationClip: 重點(diǎn)檢查是否有重復(fù)資源.
6)Mesh: 重點(diǎn)檢查是否有重復(fù)資源.
項(xiàng)目中可能遇到的問(wèn)題
1.Device.Present:
1)GPU的presentdevice確實(shí)非常耗時(shí),一般出現(xiàn)在使用了非常復(fù)雜的shader.
2)GPU運(yùn)行的非常快,而由于Vsync的原因,使得它需要等待較長(zhǎng)的時(shí)間.
3)同樣是Vsync的原因,但其他線程非常耗時(shí),所以導(dǎo)致該等待時(shí)間很長(zhǎng),比如:過(guò)量AssetBundle加載時(shí)容易出現(xiàn)該問(wèn)題.
4)Shader.CreateGPUProgram:Shader在runtime階段(非預(yù)加載)會(huì)出現(xiàn)卡頓(華為K3V2芯片).
5)StackTraceUtility.PostprocessStacktrace()和StackTraceUtility.ExtractStackTrace(): 一般是由Debug.Log或類似API造成,游戲發(fā)布后需將Debug API進(jìn)行屏蔽。
2.Overhead:
1)一般情況為Vsync所致.
2)通常出現(xiàn)在Android設(shè)備上.
3.GC.Collect:
原因:
1)代碼分配內(nèi)存過(guò)量(惡性的)
2)一定時(shí)間間隔由系統(tǒng)調(diào)用(良性的).
占用時(shí)間:
1)與現(xiàn)有Garbage size相關(guān)
2)與剩余內(nèi)存使用顆粒相關(guān)(比如場(chǎng)景物件過(guò)多,利用率低的情況下,GC釋放后需要做內(nèi)存重排)
4.GarbageCollectAssetsProfile:
1)引擎在執(zhí)行UnloadUnusedAssets操作(該操作是比較耗時(shí)的,建議在切場(chǎng)景的時(shí)候進(jìn)行)。
2)盡可能地避免使用Unity內(nèi)建GUI,避免GUI.Repaint過(guò)渡GCAllow.
3)if(other.tag == a.tag)改為other.CompareTag(a.tag).因?yàn)閛ther.tag為產(chǎn)生180B的GC Allow.
4)少用foreach,因?yàn)槊看蝔oreach為產(chǎn)生一個(gè)enumerator(約16B的內(nèi)存分配),盡量改為for.
5)Lambda表達(dá)式,使用不當(dāng)會(huì)產(chǎn)生內(nèi)存泄漏.
5.盡量少用LINQ:
1)部分功能無(wú)法在某些平臺(tái)使用.
2)會(huì)分配大量GC Allow.
6.控制StartCoroutine的次數(shù):
1)開(kāi)啟一個(gè)Coroutine(協(xié)程),至少分配37B的內(nèi)存.
2)Coroutine類的實(shí)例 -> 21B.
3)Enumerator -> 16B.
7.使用StringBuilder替代字符串直接連接.
8.緩存組件:
1)每次GetComponent均會(huì)分配一定的GC Allow.
2)每次Object.name都會(huì)分配39B的堆內(nèi)存.
9.我們?cè)谟^察數(shù)據(jù)時(shí),需要觀察的目標(biāo)有如下幾點(diǎn):
CPU:
每幀都具有20B以上內(nèi)存分配的選項(xiàng) 。
GC相關(guān)的問(wèn)題和優(yōu)化,在之后我們會(huì)詳細(xì)的介紹。
2. Time ms:
注意占用5ms以上的選項(xiàng)
總結(jié)
- 上一篇: GELU函数的近似
- 下一篇: Box2d源码学习十四TOI之碰撞时间的