Unity3D性能優化——工具篇
來自專欄遊戲開發入門指南——Unity+53 人贊了文章
本篇難度:☆☆
性能優化是遊戲項目開發中一個重要且必須的元素。用戶和項目的需求在並且會持續增長。而即便在硬體設備高速發展的今天,遊戲特效、畫質、場景複雜度的需求也都向著榨乾硬體性能的趨勢提升,無論研發團隊有多麼豐富的經驗積累,性能優化永遠是一個非常棘手而又無法繞開的問題。
實際上,通過百度、谷歌、知乎可以搜到大把關於Unity性能優化的文章,但大多只是簡單的論述、介紹、翻譯和轉載,或針對某中特定問題優化方式的教程。因此,我們在這裡推出Unity3D性能優化系列文章,旨在給讀者提供一個全面、易懂、可操作的unity優化教程,以便初學者學習使用。
在這裡,我們的第一篇文章,主要作為一個引導,通過講解對unity優化工具的了解及使用,給讀者提供在實際項目中,進行遊戲性能優化的流程和思路。
- 對於Unity性能優化,官方有非常好的教程,(參見官方教程)。如果英文水平一般,可以參考官方教程翻譯。
- 同時你也可以去看看騰訊是如何做Unity手游性能優化的。
- 以及通過第三方優化平台的遊戲性能分析報告來了解遊戲開發中性能優化的主要方式及方向。
遊戲性能簡述
提起遊戲性能,首先要提到的就是,不僅開發人員,所有遊戲玩家都應該會接觸到的一個名詞:幀率(Frame rate)。
幀率是衡量遊戲性能的基本指標。在遊戲中,「一幀」便是是繪製到屏幕上的一個靜止畫面。繪製一幀到屏幕上也叫做渲染一幀。每秒的幀數(fps)或者說幀率表示GPU處理時每秒鐘能夠更新的次數。高的幀率可以得到更流暢、更逼真的動畫。
現階段大多數遊戲的理想幀率是60FPS,其帶來的交互感和真實感會更加強烈。通常來說,幀率在30FPS以上都是可以接受的,特別是對於不需要快速反應互動的遊戲,例如休閑、解密、冒險類遊戲等。有些項目有特殊的需求,比如VR遊戲,至少需要90FPS。當幀率降低到30FPS以下時,玩家通常會有不好的體驗。
但在遊戲中重要的不僅僅幀率的速度,幀率同時也必須非常穩定。玩家通常對幀率的變化比較敏感,不穩定的幀率通常會比低一些但是很穩定的幀率表現更差。
雖然幀率是一個我們談論遊戲性能的基本標準,但是當我們提升遊戲性能時,更因該想到的是渲染一幀需要多少毫秒。幀率的相對改變在不同範圍會有不同的變化。比如,從60到50FPS呈現出的是額外3.3毫秒的運行時間,但是從30到20FPS呈現出的是額外的16.6毫秒的運行時間。在這裡,同樣降低了10FPS,但是渲染一幀上時間的差別是很顯著的。
我們還需要了解渲染一幀需要多少毫秒才能滿足當前幀率。通過公式 1000/(想要達到的幀率)。通過這個公式可以得到,30FPS必須在33.3毫秒之內渲染完一幀,60FPS必須在16.6毫秒內渲染完一幀。
渲染一幀,Unity需要執行很多任務。比如,Unity需要更新遊戲的狀態。有一些任務在每一幀都需要執行,包括執行腳本,運行光照計算等。除此之外,有許多操作是在一幀執行多次的,例如物理運算。當所有這些任務都執行的足夠快時,我們的遊戲才會有穩定且理想的幀率。當這些任務執行不滿足需求時,渲染一幀將花費更多的時間,並且幀率會因此下降。
知道哪些任務花費了過多的時間,是遊戲性能問題的關鍵。一旦我們知道了哪些任務降低了幀率,便可以嘗試優化遊戲的這一部分。這就是為什麼性能分析工具是遊戲優化的重點之一。
Unity3d性能分析工具
工欲善其事必先利其器,這裡我們來講解Unity3D優化所需的工具
如果遊戲存在性能問題,遊戲運行就會出現緩慢、卡頓、掉幀甚至直接閃退等現象。在我們嘗試解決問題前,需要先知道其問題的起因,而嘗試不同的解決方案。若僅靠猜測或者依據自身原有的經驗去解決問題,那我們可能會做無用功,甚至引申出更複雜的問題。
在這些時候我們就需要用到性能分析工具,性能分析工具主要測試遊戲運行時各個方面性能,如CPU、GPU、內存等。通過性能分析工具,我們能夠透過遊戲運行的外在表現,獲取內在信息,而這些信息便是我們鎖定引起性能問題的關鍵所在。
在我們進行Unity性能優化的過程中,最主要用的到性能分析工具包括,Unity自帶的Unity Profile,IOS端的XCode ,以及一些第三方插件,如騰訊推出的UPA性能分析工具。
我們主要針對Unity Profile進行講解,之後也會略微介紹另外一些性能分析工具。
Unity Profile
Unity Profile是Unity中最常用的官方性能分析工具,在使用Unity開發遊戲的過程中,藉助Profiler來分析CPU、GPU及內存使用狀況是至關重要的。
首先我們來了解Unity Profile的面板:
我們通過Window——>Profiler來激活Unity Profile面板在下圖中我們可以看到Unity Profile面板,其中有很多profilers,每個profiler顯示我們當前項目一個方面的信息,如CPU、GPU、渲染(Rendering)、內存(Memory)、聲音(Audio)、視屏(Video)、物理(Physics)、ui及全局光照(global illumination)。
當項目運行時,每個profilers會隨著運行時間來顯示數據,有些性能問題是持續性的,有些僅在某一幀中出現,還有些性能問題可能會隨時間推移而逐漸顯出出來。
在面板的下半部分顯示了我們選中的profilers當前幀的詳細內容,我們可以通過選擇列標題,通過這一列的信息值來排序。
在CPU usage profiler中的列表題分別為:Total:當前任務的時間消耗占當前幀cpu消耗的時間比例。 Self:任務自身時間消耗占當前幀cpu消耗的時間比例。 Calls:當前任務在當前幀內被調用的次數。 GC Alloc:當前任務在當前幀內進行過內存回收和分配的次數。 Time ms:當前任務在當前幀內的耗時總時間。 Self ms:當前任務自身(不包含內部的子任務)時間消耗。當我們在層級視圖中點擊函數名字時,CPU usage profiler將在Profiler窗口上部的圖形視圖中高亮顯示這個函數的信息。比如我們選中Cameta.Render,Rendering的信息就會被高亮顯示出來。
我們可以Profiler的左下的下拉菜單中選擇Timeline。
Timeline顯示了兩件事:cpu任務的執行順序和哪個線程負責什麼任務。線程允許不同的任務同時執行。當一個線程執行一個任務時,另外的線程可以執行另一個完全不同的任務。和Unity的渲染過程相關的線程有三種:主線程,渲染線程和worker threads。了解哪個線程負責哪些任務的用處非常之大,一旦我們知道了在哪個線程上的任務執行的速率最低,那麼我們就應該集中優化在那個線程上的操作。
以上所顯示的數據依賴於我們當前選擇的profiler。例如,當選中內存時,這個區域顯示例如遊戲資源使用的內存和總內存佔用等。如果選中渲染profiler,這裡會顯示被渲染的對象數量或者渲染操作執行次數等數據。
這些profiler會提供很多詳細信息,但是我們並不總需要使用所有的profiler。實際上,我們在分析遊戲性能時通常只是觀察一個或者兩個profiler,而不需要觀察的我們可以通過右上角的」X」關閉,如果需要在添加回來,可以通過左上角Add Profiler。
例如,當我們的遊戲運行的比較慢時,我們可能一開始先查看CPU usage profiler,CPU usage profiler也是在我們進行優化分析時最常用的Profiler。當然,除了CPU usage profiler,Unity Profiler中其他的Profiler在一些場合也非常的有用,比如GPU、內存、渲染等,其使用方法和CPU usage profiler也是大同小異,可以按照以上的步驟來查看並學習。
我們在觀察數據時,需要觀察的目標有如下幾點:
CPU:
1. GC Allow: 任何一次性內存分配大於2KB的選項。 每幀都具有20B以上內存分配的選項 。GC相關的問題和優化,在之後我們會詳細的介紹。
2. Time ms:
注意佔用5ms以上的選項
內存
1. Texture: 檢查是否有重複資源和超大內存是否需要壓縮等.。2. AnimationClip: 重點檢查是否有重複資源.。3. Mesh: 重點檢查是否有重複資源。實際項目中的優化建議
在了解了Unity Profiler後,現在我們在一個實際項目中來進行一次性能分析。同時來了解一般在實際項目中,主要會引起也是我們主要去觀察的性能問題出現在什麼地方。
以下是我做的一個簡單的遊戲項目,並未做任何性能優化並且有大量引起性能問題的代碼,可以更方便大家觀察其性能問題,在之後我會把工程上傳到github供初學者下載分析。
我們來看一下在CPU usage profiler面板中的可觀察項,在項目中我們可以先關閉VSync垂直同步來提高幀率。
下圖中我關閉了除VSync之外的顯示,可以看到VSync的消耗
具體步驟是edit->project settings->Quality,在Inspector面板中,V Sync count選擇don』t Sync.
我們來簡單的介紹一下什麼是垂直同步,以及關閉它之後會發生什麼。
要理解垂直同步,首先明白顯示器的工作原理。顯示器上的所有圖像都是單個像素組成了水平掃描線,水平掃描線在垂直方向的堆積形成了完整的畫面,無論是隔行掃描還是逐行掃描,顯示器都有兩種同步參數——水平同步和垂直同步。
垂直和水平是CRT顯示器中兩個基本的同步信號,水平同步信號決定了CRT畫出一條橫越屏幕線的時間,垂直同步信號決定了CRT從屏幕頂部畫到底部,再返回原始位置的時間,而垂直同步代表著CRT顯示器的刷新率水準。 在遊戲項目中,如果我們選擇等待垂直同步信號也就是打開垂直同步,在遊戲中或許性能較強的顯卡會迅速的繪製完一屏的圖像,但是沒有垂直同步信號的到達,顯卡無法繪製下一屏,只有等85單位的信號到達,才可以繪製。這樣FPS自然要受到刷新率運行值的制約。 而如果我們選擇不等待垂直同步信號,那麼遊戲中繪製完一屏畫面,顯卡和顯示器無需等待垂直同步信號就可以開始下一屏圖像的繪製,自然可以完全發揮顯卡的實力。 但是,正是因為垂直同步的存在,才能使得遊戲進程和顯示器刷新率同步,使得畫面更加平滑和穩定。取消了垂直同步信號,固然可以換來更快的速度,但是在圖像的連續性上勢必會打折扣。 需要注意,LCD顯示器其實也是存在刷新率的,但其機制與CRT不同,這裡不做過多贅述,但是垂直同步和水平同步對於LCD顯示器來說,一樣是有必要的。
在關閉垂直同步後,我們繼續看我們的項目
可以看到,我們以Total和Time ms排序,在圖中拉黑的項(Camera Render)始終排在最前面。
Camera Render是相機渲染工作的CPU佔用量,在實際項目中,渲染是最常見的引起性能問題的原因。 而因為渲染而引起的性能問題的優化是一個非常大的工程,這方面的優化方法在我們後續的文章中會有詳細的教程去學習和分析。在這裡,我們只需要先了解。我們這個項目的優化中,無疑,渲染造成的性能損耗是一個大頭。如果說,在我們性能分析中,渲染已經沒有什麼問題,那麼我們接下來要重點觀察的就是GC,也就是垃圾回收性能分析。
我們按照GC Alloc的順序來顯示,可以看到下圖。在之前我們提到過,GC Alloc中,任何一次性內存分配大於2KB的選項,每幀都具有20B以上內存分配的選項 ,是需要我們重點關注的,顯而易見,我們的項目中,對於GC的優化,也有很大的問題。關於CG的問題,我們會在下一篇Unity3D性能優化——CPU篇中,詳細的介紹。這裡我們大致介紹一下GC的機制,要想了解垃圾回收如何工作以及何時被觸發,我們首先需要了解unity的內存管理機制。Unity主要採用自動內存管理的機制,開發時在代碼中不需要詳細地告訴unity如何進行內存管理,unity內部自身會進行內存管理。
Unity內部有兩個內存管理池,堆內存和棧內存,垃圾回收主要是指堆上的內存分配和回收,unity中會定時對堆內存進行GC操作。 當堆內存上一個變數不再處於激活狀態的時候,其所佔用的內存並不會立刻被回收,不再使用的內存只會在GC的時候才會被回收。 每次運行GC的時候,GC會檢查堆內存上的每個存儲變數,對每個變數會檢測其引用是否處於激活狀態,如果變數的引用不再處於激活狀態,則會被標記為可回收,被標記的變數會被移除,其所佔有的內存會被回收到堆內存上。 GC操作是一個極其耗費的操作,堆內存上的變數或者引用越多則其運行的操作會更多,耗費的時間越長。
如果我們也排除了GC的問題, 那麼再接下來,我們就要考慮到是否是腳本的一些問題造成性能損耗。
這裡的腳本,可能是我們自己寫的代碼,也有可能是我們使用的一些插件的代碼。在CPU usage profiler面板中,我們可以關注Script這一項。
如果在一個很慢的幀中,一大部分時間被腳本運行所消耗,這意味著這些慢的腳本可能就是引起性能問題的主因。我們可以更加深入的分析數據來確認。首先我們按照Time ms來排序,然後選擇信息列表中的項目,如果是用戶腳本的函數,那麼在Profiler上方會有高亮腳本的部分。這種情況,說明遊戲的性能問題是和用戶腳本相關的,如下圖中的顯示,這部分腳本性能問題一定是與我們FixedUpdate有關。
同時,我們還可以再關注一些物理、ui方面的性能問題。
在上面我們討論的,是幾種最常見的性能問題,在實際項目優化中,如果有性能問題也逃不開這些,如果在這些方向都已經達到了我們的要求,但我們的遊戲仍然有性能問題,我們應該遵循上面的方法解決問題:收集數據——>使用CPU usage profiler查看信息——>找到引起問題的函數。一旦我們知道了引起問題函數的名字,我們便可以針對性的,對其進行優化處理。
其他性能分析工具
在開頭我們說過,在我們進行Unity性能優化的過程中,最主要用的到性能分析工具包括,Unity自帶的Unity Profile,IOS端XCode Capture GPU frame以及一些第三方插件,如騰訊推出的UPA性能分析工具。
這裡我們簡單的介紹一下XCode和UPA.
Xcode是 Mac OS X上的集成開發工具。在我們打包Unity IOS的項目時,必須使用到Xcode來幫助我們打包及發布。
Xcode的功能也十分的強大,在我們開發IOS端時,可以使用其GPU frame Capture 功能為我們的項目進行性能優化分析。
在unity中,我們打包時在Run In Xcode as 選擇debug模式,並且勾選Development Build
打包完成後,使用Xcode打開文件,在Xcode中選擇Product ——> Scheme——> Manage Schemes然後會出現如下界面我們雙擊這個項目會出現如下界面然後我們在左側選中Run,然後在右側面板選擇Options在GPU frame Capture中選擇OpenGL ES或者Metal。在Debug模式下運行項目,當項目在真機上完全載入後,就可以進入Debug Navigator(View ——> Navigators ——> Show Debug Navigator)以下是GPU frame Capture具體功能的界面,在圖形化界面中,可以在遊戲運行時清晰的了解到CPU、GPU、內存的使用情況。
XCode的Capture GPU frame功能能高效且定量地定位到GPU中shader的消耗。UPA是騰訊和Unity聯合打造的一款性能分析工具,據說王者榮耀的性能優化分析就有使用到UPA,具體的使用方法可以通過客戶端性能測試【騰訊WeTest】去了解。
好了,本期文章就到這裡,旨在拋磚引玉,下一篇我們就會進行在Unity中CPU、GPU及內存優化方面的探索及優化方法的詳細介紹。
推薦閱讀:
※U3D常用的類和結構體
※Community Help Sydney-
※Community of inquiry model(From EduTech Wiki)