手機游戲的性能異常重要,特別是對於快節奏的動作游戲。你可能知道,我們現在在做一款安卓/IOS平台的彈球游戲,他的特點是在一個3D世界中迅速的物理引擎結合完整的角色動畫,任何彈球游戲需要60fps的性能,為了實現它我們需要一點一滴地壓榨設備CPU。
所以,我們面對的挑戰是,如何在至少60fps的情況下保證游戲運行流暢。只要降低到60fps以下將會減少一半的幀率!60fps-30fps之間切換意味着一個嚴重的hick-up。而且如果頻繁發生將會帶來不好的游戲體驗。
極限情況,我們想要支持最老的iPhone 3GS,而且要運行在30fps以上。
Above: Momo and Fry are beating up two owl bandits – 四個角色同時出現在屏幕中。
所以性能是非常重要的,當你用Unity開發安卓/Iphone游戲時怎么提高性能?這里有四個我們過去用過的Unity工具,用來優化iPhone/安卓版本的Momonga的幀率。
1.使用Proformance Profiler
第一件事情要做的是看,看你想要提高性能游戲的Unity Profiler,它是一個Unity Pro的特性,讓你分析性能瓶頸。分析器是一個無價的工具,通過它,你可以確定所有的幀率問題出自哪里。你在你的目標設備上運行游戲,然后在PC上運行分析器,當你啟動游戲時,分析器就會顯示出性能數據。
方便的地方是你可以在windows機器上運行Profiler分析一台iPhone或者iPad。
在你的設備上使用Profiler,在開發者模式簡單建立一個游戲。通過Unity文檔:
為了能夠連接一個設備,設備必須在BuildSettings對話框中找到Development Build並勾選,在這里可能還需要勾選Editor和Player Autoconnect。
當你玩游戲時分析器顯示CPU使用情況的曲線圖,簡單的保持你的設備和你的開發機器連接,然后玩游戲,分析器會實時的顯示所有的瓶頸和hick-ups。分析器會在一些地方分類顯示活動:渲染、腳本、物理、垃圾回收、垂直同步和其他。
對於手機游戲來說,問題通常和渲染有關,例如Momonga,渲染耗費了40%的CPU,這是一個需要我們注意的地方:我們嘗試減少頂點和poly數量。
當加載場景時在腳本中會偶有峰值-但在加載場景時有一個低幀率這不是不尋常的。你依然可以看到一些峰值,大部分是物理引擎相關的,這將是我們進一步提高性能下一步關注的。
2.靜態批處理(Static batching)
靜態批處理是Unity的一個特性,節省了很多CPU循環。它的工作像這樣。
每次一個對象被渲染都會有一個“Draw Call”-主要是一條告訴CPU或者GPU的命令,這個對象需要渲染。Unity發出數條drawcalls,然后把它們放在其他drawcalls頂部,使場景完整。但是,每個Draw Call都有CPU開銷,而你想要盡可能的最小化Draw Call,將一個draw call比作一個需要油漆的空白畫布,你是想要油漆1個呢還是50個呢?我是這樣想的。
批處理,它確保沒有不必要的draw call被使用,Batching有兩種口味:靜態(Static)和動態(Dynamic)。
靜態給你最好的性能,所以我們總是使用靜態批處理。學習細節看這里。
有效的使用靜態批處理你要盡可能少的使用不同的材質。為了實現這個你需要整合你的材質到一張大的紋理里,我們選擇使用頂點顏色和所有物體有同一模式的紋理,頂點着色允許你給每個頂點一個顏色,刪除需要實時光照,顏色將會通過我們藝術家直接畫在模型上。這就意味着我們所有的道具和環境中的物體使用同樣的材質,靜態批處理棒棒的。
Above:靜態批處理運行時,注意這些物體在一個單獨的Draw Call中渲染。
使用頂點顏色僅僅看上去有一點減少,所以我們有一對乘以頂點顏色的紋理給物體多一點“紋理”。
Above:頂點顏色和一個模式紋理
最后一步是添加一個光線映射在場景中,因為我們幾乎沒有給物體本身使用任何紋理內存,我們可以有一個相當詳細的沒有內存問題的光線映射。
靜態批處理需要你在Ojbect Properties面板選中“Static”,它只能用在場景中沒有移動、旋轉或者縮放的物體上。
3.動態批處理(Dynamic Batching)
當靜態批處理不是最佳選擇時,動態批處理可以挽救局面,事實上,它總是用在哪些不是靜態的物體上,使用它你只要使用盡量小的物體和盡量 少的頂點。
批處理動態物體每個頂點有一些開銷,所以批處理僅支持網格包含且少於900頂點的網格物體。
我們的着色器使用頂點位置、UV和顏色,所以我們的每個物體可以有高達300個頂點。
一些來自Unity Manual有用的提示:
- 批處理動態物體每個頂點會有一些開銷,所以批處理僅被允許使用在網格數量包含且小於900頂點屬性。
- 如果你的着色器是是用的是頂點位置, 法線和單一的UV,你可以批處理300個頂點,如果你的着色器是用的是頂點位置, 法線, UV0, UV1 和切向量,你只能處理180個頂點。
- 不要使用縮放尺寸,分別擁有縮放尺寸(1,1,1)和(2,2,2)的物體不會進行批處理。
- 統一縮放尺度的物體不會與非統一縮放尺度的物體進行批處理。
- 使用縮放尺度(1,1,1,)和(1,2,1)的兩個物體不會進行批處理,但是使用縮放尺度(1,2,1)和(1,3,1)的兩個物體將可以進行批處理。
- 使用不同材質的實例化物體將會導致批處理失敗。
- 擁有lightmap的物體含有額外(隱藏)的材質屬性,比如:lightmap的偏移和縮放系數等。所以擁有lightmap的物體將不會進行批處理(除非他們指向lightmap的同一部分)。
- 多通道的shader會妨礙批處理操作。比如,幾乎unity中所有的着色器在前向渲染中都支持多個光源,並為他們有效的開辟多個通道。
- 預設體的事例會自動使用相同的網格模型和材質。
還有一些重要的小提示:如果一個物體有一個動畫但是有一部分從來不動,你可以標記那一部分為靜態的,而且他將不會影響動畫。
Dynamic Batching is very useful for star pickups and other small objects that are animated but are otherwise the same in the scene.
動態批處理對於star pickups和一些運動的但在同一場景的小物體是非常有用的。
4.音頻最佳化(Audio Optimizations)
我們遭遇了一些嚴重的性能問題,之后我們挖掘問題所在,發現罪魁禍首就是音頻。
Unity組件文檔中有這樣一段話關於音頻剪輯:
一般原則,壓縮音頻(或者模塊)適用於長文件像背景音樂或者對話框中,而Native用於短的聲音音效更好。
這是一個好的建議,但是有一個問題,我們發現播放有不正確的壓縮設置的音頻會擾亂你的內存使用或造成CPU峰值。
仔細閱讀Unity Manual幫助我們定位了問題所在:
“Note that only one hardware audio stream can be decompressed at a time.”
“請注意一次只有一個硬件音頻流可以解壓。”
我們看見CPU峰值是因為iPhone使用硬件解碼器一次只能解壓一個音頻文件。
這個可以通過使用“Decompress On Load”設置來解決,性能提升了,但是它造成了內存飛漲,所以真正需要時才使用它。
當用不同類型的音頻,我們為了獲得最佳性能的一些經驗法則:
- 短剪輯 - 本地
- 長的(或循環的)剪輯 -壓縮在內存中
- 音樂 - disc流(Stream from disc)
- 造成CPU峰值的文件 - 在加載時解壓
如果你遵循這些規則,音頻應該不會給你帶來太多的麻煩,除非你一次啟動了所有的聲音文件。
結論
對於手機游戲最重要的事是保持你的三角形、頂點和drawcall盡可能的少,如果你遇到性能問題,Unity提供了很多工具讓你的游戲重回掌控,它將肯定不會辜負你閱讀文檔。
這就是我們現在所有的提示。
你提升性能的小技巧是什么?在評論里讓我們知道。