? ? ? ? 在剛開始做游戲的時(shí)候疗疟,在網(wǎng)上亂七八糟找些素材就放進(jìn)去了,無論是3D還是2D案糙,到后來都會出現(xiàn)各種過多渲染限嫌,內(nèi)存占用太高等情況。電腦上跑跑也許問題不明顯时捌,一到手機(jī)上就漏洞百出怒医。所以,正確處理優(yōu)化是很重要的一環(huán)奢讨。
附注:以下方法針對性不統(tǒng)一稚叹,有些方法優(yōu)化了游戲性能,增強(qiáng)了畫面要求拿诸,但是有可能也相對增加了內(nèi)存的占用扒袖。至于怎么取舍,大家根據(jù)自己項(xiàng)目來吧
2D—Texture
在制作2d游戲的時(shí)候亩码,如果我們使用NGUI來制作界面季率,那么必然會用到打包圖集,簡單來說圖集的優(yōu)點(diǎn)在于能將所有的圖片合成一張大圖描沟,而我們引擎渲染的時(shí)候飒泻,就只用繪制這一張圖。而UGUI并沒有加入大包的工作吏廉,我們可以和NGUI一樣使用TexturePacker來打包圖集泞遗。Unity商店里面也同樣有一個(gè)免費(fèi)的插件TexturePacker Importer,我們只需將打包好的圖集文件添加到Unity中,就能自動幫我們將每個(gè)圖片切割開迟蜜,當(dāng)然刹孔,也可以自己通過SpriteEditor來切割,之后便可以直接使用娜睛。
做一個(gè)測試,我們將插件中原本作為單獨(dú)存在的圖片加入到場景中卦睹,有多少張圖畦戒,就繪制了多少次,圖中左邊SetPass calls為5结序,而將圖集中的圖片加入進(jìn)去障斋,同樣的個(gè)數(shù)甚至更多的情況下,SetPass calls為1徐鹤,在游戲中如果使用了大量UI垃环,那么對圖片的打包是必要的。
幀數(shù)
FPS是我們衡量一個(gè)游戲性能的標(biāo)準(zhǔn)返敬。有時(shí)候我們做一個(gè)游戲遂庄,不同的設(shè)備的處理器的效果可能不一樣,如果沒有限制劲赠,那么達(dá)到幾百也是有的涛目。如在《英雄聯(lián)盟》中秸谢,我們經(jīng)常看到FPS的值幾十到幾百不等的都有霹肝。但是有時(shí)候估蹄,我們的游戲并不需要那么高的幀率,在手機(jī)上過高的幀也會導(dǎo)致游戲卡頓沫换,耗電量高等情況臭蚁。所以,一般情況下讯赏,我們可以針對FPS做一個(gè)限制刊棕。
不僅如此,我們的游戲有時(shí)候需要在后臺也運(yùn)行待逞,保持暫停的情況甥角,這時(shí)候游戲作為靜止的畫面,顯然是不需要這么高的幀數(shù)的识樱,那么我我們在此時(shí)可以判斷在后臺的情況下嗤无,設(shè)置幀率為1,減少消耗怜庸。
另外当犯,幀率的大小也受到垂直同步的影響,垂直同步直接影響幀率割疾,優(yōu)先級高于代碼嚎卫,也就是說,如果設(shè)置了垂直同步宏榕,我們在代碼中編寫的設(shè)置垂直同步的語句可能就會失效拓诸。如垂直同步設(shè)置值為1,幀率就為60麻昼,為2奠支,則幀率為30。
是否設(shè)置垂直同步可以在Edit-PlayerSetting-Quality中找到?V-Sync 來設(shè)置抚芦。
LOD Group
LOD Group的作用的倍谜,就是在不同的距離下顯示不一樣的內(nèi)容。我們做一個(gè)測試叉抡,在場景中分別建立Capsule尔崔,Cube,Sphere3個(gè)物體褥民,將Cube和Sphere作為子物體添加到Capsule下季春,給Capsule添加LOD Group, 然后分別對應(yīng)設(shè)置轴捎。如圖:
大家在場景中測試鹤盒,拖動攝像機(jī)蚕脏,發(fā)現(xiàn)不同的距離顯示的是不一樣的物體。那么針對這樣的需求侦锯,我們在游戲中驼鞭,遠(yuǎn)距離的物體就不需要高面數(shù)的模型,由此我們可以使用低模來替代尺碰,達(dá)到優(yōu)化的效果挣棕。雖然有時(shí)候我們會用這個(gè),但是LOD也會相應(yīng)的增加內(nèi)存亲桥。
MipMap
Mipmap類似于LOD洛心,但LOD是針對于模型來處理,Mip是針對貼圖紋理來處理题篷。
在使用MipMap時(shí)词身,貼圖會根據(jù)攝像機(jī)距離的遠(yuǎn)近,選擇使用不同精度的貼圖番枚。但同樣的法严,雖然MipMap可以優(yōu)化顯存帶寬,用來減少渲染需求葫笼,但是和LOD一樣會增加內(nèi)存深啤。
MipMap可以應(yīng)用在跑酷游戲上,遠(yuǎn)距離與近距離的貼圖可以通過這個(gè)來優(yōu)化路星。當(dāng)然溯街,用或不用,或者怎么用洋丐,都應(yīng)該根據(jù)需求來判斷呈昔。
ObjectPool
使用對象池是很重要的一個(gè)點(diǎn)。例如垫挨,我們在做跑酷游戲的時(shí)候韩肝,永無止境的道路是不可能一來就生成好了的,也不會一邊跑一邊生成九榔,這樣會大大降低游戲性能。而對象池正好彌補(bǔ)這一點(diǎn)涡相。
使用對象池的方法哲泊,簡單來說就是 我們在游戲加載時(shí)便開始創(chuàng)建出大部分會用到的對象,于是在使用的時(shí)候催蝗,修改對象的位置讓他出現(xiàn)在攝像機(jī)的視野中切威,當(dāng)不需要的時(shí)候修改位置移動到視野外。
這樣避免了每次生成一個(gè)物體丙号,引擎都要去重新渲染一次先朦。對象池的每個(gè)對象需要我們用代碼來管理缰冤,這也是面向?qū)ο缶幊讨匾囊稽c(diǎn)。
Draw Call合并
合并分為靜態(tài)合并和動態(tài)合并2種喳魏。
Unity為我們完成了動態(tài)操作棉浸,也就是說不需要我們手動去完成,只要使用相同材質(zhì)的對象刺彩,都可以被合并迷郑,且保持旋轉(zhuǎn)移動i自由。但動態(tài)合并也對模型的頂點(diǎn)有要求创倔。如需要相同縮放比例嗡害,模型點(diǎn)數(shù)目限制,單pass的shader等畦攘。
靜態(tài)合并需要我們自己操作霸妹,對于模型,我們勾選組件MeshRender上的Batching Static知押,也可以通過UnityEngine.StaticBatchingUtility方法來實(shí)現(xiàn),具體可以查閱官網(wǎng)叹螟。通過各類書和資料得出的結(jié)論,最終推薦代碼+動態(tài)方法完成合并朗徊。
至于為什么要合并首妖,也是因?yàn)楸苊庵貜?fù)對相同的材質(zhì)進(jìn)行多次渲染,這樣可以降低顯卡的計(jì)算量爷恳,提高性能有缆。
優(yōu)化代碼
代碼也會影響性能?那是肯定的温亲。如我們在腳本種使用剛體組件的時(shí)候棚壁,可以直接使用GetComponent<Rigidbody>()來調(diào)用剛體組件的方法和屬性,但是我們沒一次get的時(shí)候栈虚,或多或少也會有一點(diǎn)性能的消耗袖外,因?yàn)槲覀冊诟嬖V我們的設(shè)備,需要去get這個(gè)組件魂务,那么設(shè)備就會去找曼验,找到了再拿過來,但是這是屬于一次性的用法粘姜。對于這種鬓照,我們也一般會事先聲明 一個(gè) Rigidbody 的對象,將GetComponent<RIgidbody>()賦值給對象孤紧,這種方法再常用不過豺裆。雖然好像一點(diǎn)點(diǎn)看不出來什么影響,但是如果調(diào)用次數(shù)太頻繁号显,建議使用后面的方法臭猜。
同樣的道理躺酒,對于一些固定的數(shù)組,如果需要頻繁遍歷數(shù)組蔑歌,也可以將數(shù)組的值記錄下來羹应,不必每次遍歷都去獲取。類似的還有Unity 中的Find(),FindChild()等方法丐膝,在多次使用對象的時(shí)候盡量避免重復(fù)獲取量愧。
還有關(guān)于for 和 foreach方法,網(wǎng)上已經(jīng)有很多介紹了帅矗,總歸一句話偎肃,update函數(shù)里面最好還是別用foreach。
光照(不完整)
光照問題是個(gè)很嚴(yán)肅的話題浑此,之前弄了一個(gè)小項(xiàng)目累颂,但是發(fā)現(xiàn)Batch和set Pass竟然最高到了300,最低也是100多凛俱,在手機(jī)上這種情況應(yīng)該無法忍受紊馏。后來發(fā)現(xiàn),因?yàn)橛螒驁鼍爸械墓庹帐沁x擇的RealTime蒲犬,也就是說是用的實(shí)時(shí)陰影朱监,物體太多的時(shí)候,陰影的渲染也會很多原叮,所以在嘗試了很多方法后選擇把光照弄成Baked赫编,然后通過烘焙光照貼圖來完成。這樣場景中不添加光照奋隶,也能看見場景擂送,但是缺失了陰影,至于針對陰影的解決辦法唯欣,正在鉆研嘹吨,還沒找到很好的解決方案。
總之境氢,對于光照來說蟀拷,適當(dāng)選擇光照方式,會對游戲性能有很大影響萍聊,要慎重選擇實(shí)時(shí)陰影的光照匹厘。
如果有錯(cuò)或疑問,歡迎提出脐区,我會做改正。