1. 程式人生 > >#遊戲unity-VR場景漫遊#遊戲中的優化(二)

#遊戲unity-VR場景漫遊#遊戲中的優化(二)

這篇文章接著上一篇的內容進行整理。

畫素優化

畫素優化的重點在於減少overdraw。之前提過,overdraw指的就是一個畫素被繪製了多次。關鍵在於控制繪製順序。

Unity還提供了檢視overdraw的檢視,在Scene檢視的Render Mode->Overdraw。當然這裡的檢視只是提供了檢視物體遮擋的層數關係,並不是真正的最終螢幕繪製的overdraw。也就是說,可以理解為它顯示的是如果沒有使用任何深度檢驗時的overdraw。這種檢視是通過把所有物件都渲染成一個透明的輪廓,通過檢視透明顏色的累計程度,來判斷物體的遮擋。
顏色越是濃重的地方表示overdraw越嚴重,這意味著效能將會受到很大影響。

控制繪製順序

在PC上,資源無限,為了得到最準確的渲染結果,繪製順序可能是從後往前繪製不透明物體,然後再繪製透明物體進行混合。但在移動平臺上,這種會造成大量overdraw的方式顯然是不適合的,我們應該儘量從前往後繪製。從前往後繪製之所以可以減少overdraw,都是因為深度檢驗的功勞。

在Unity中,那些Shader中被設定為“Geometry” 佇列的物件總是從前往後繪製的,而其他固定佇列(如“Transparent”“Overla”等)的物體,則都是從後往前繪製的。這意味這,我們可以儘量把物體的佇列設定為“Geometry” 。

而且,我們還可以充分利用Unity的佇列來控制繪製順序。例如,對於天空盒子來說,它幾乎覆蓋了所有的畫素,而且我們知道它永遠會在所有物體的後面,因此它的佇列可以設定為“Geometry+1”。這樣,就可以保證不會因為它而造成overdraws。

警惕透明物體

如果要得到正確的渲染效果,就必須從後往前渲染(這裡不討論使用深度的方法),而且拋棄了深度檢驗。這意味著,透明物體幾乎一定會造成overdraws。如果我們不注意這一點,在一些機器上可能會造成嚴重的效能下面。例如,對於GUI物件來說,它們大多被設定成了半透明,如果螢幕中GUI佔據的比例太多,而主攝像機又沒有進行調整而是投影整個螢幕,那麼GUI就會造成螢幕的大量overdraws。

如果場景中大面積的透明物件,或者有很多層覆蓋的多層透明物件(即便它們每個的面積可以都不大),或者是透明的粒子效果,在移動裝置上也會造成大量的overdraws。這是應該儘量避免的。

處理方法——可以儘量減少視窗中GUI所佔的面積。如果實在無能為力,我們可以把GUI繪製和三維場景的繪製交給不同的攝像機,而其中負責三維場景的攝像機的視角範圍儘量不要和GUI重疊。對於其他情況,只能說,儘可能少用。當然這樣會對遊戲的美觀度產生一定影響,因此我們可以在程式碼中對機器的效能進行判斷,例如首先關閉所有的耗費效能的功能,如果發現這個機器表現非常良好,再嘗試開啟一些特效功能。

減少實時光照

對於逐畫素的光源來說,被這些光源照亮的物體要被再渲染一次。更糟糕的是,無論是動態批處理還是動態批處理對於這種逐畫素的pass都無法進行批處理,也就是說,它們會中斷批處理。

CPU優化

減少Draw Calls

對於使用同一個材質的物體,它們之間的不同僅僅在於頂點資料的差別,即使用的網格不同而已。我們可以把這些頂點資料合併在一起,再一起傳送給GPU,就可以完成一次批處理。
Unity中有兩種批處理方式:一種是動態批處理,一種是靜態批處理。對於動態批處理來說,好訊息是一切處理都是自動的,不需要我們自己做任何操作,而且物體是可以移動的,但壞訊息是,限制很多,可能一不小心我們就會破壞了這種機制,導致Unity無法批處理一些使用了相同材質的物體。對於靜態批處理來說,好訊息是自由度很高,限制很少,壞訊息是可能會佔用更多的記憶體,而且經過靜態批處理後的所有物體都不可以再移動了。

Unity進行動態批處理的條件是,物體使用同一個材質並且滿足一些特定條件。
動態批處理雖然自動得令人感動,但它對模型的要求很多——

  • 頂點屬性的最大限制為900,而且未來有可能會變。不要依賴這個資料
  • 一般來說,那麼所有物件都必須需要使用同一個縮放尺度(可以是(1, 1, 1)、(1, 2, 3)、(1.5, 1.4, 1.3)等等,但必須都一樣)。但如果是非統一縮放(即每個維度的縮放尺度不一樣,例如(1, 2, 1)),那麼如果所有的物體都使用不同的非統一縮放也是可以批處理的。這個要求很怪異,為什麼批處理會和縮放有關呢?這和Unity背後的技術有關係,有興趣的可以自行谷歌
  • 使用lightmap的物體不會批處理。多passes的shader會中斷批處理。接受實時陰影的物體也不會批處理

把四個物體的“Static Flag”勾選就可以進行靜態批處理,點選Static後面的三角下拉框,我們會看到其實這一步設定了很多東西,這裡我們想要的只是“Batching static”一項。對於合併後後的網格,Unity會判斷其中使用同一個材質的子網格,然後對它們進行批處理。

如果在靜態批處理前有一些物體共享了相同的網格,那麼每一個物體都會有一個該網格的複製品,即一個網格會變成多個網格被髮送給GPU。在上面的例子看來,就是VBO的大小明顯增大了。如果這類使用同一網格的物件很多,那麼這就是一個問題了,這種時候我們可能需要避免使用靜態批處理,這意味著犧牲一定的渲染效能。

頻寬優化

減少紋理大小

其中和優化相關的主要有“Generate Mip Maps”、“Max Size”和“Format”幾個選項。
“Generate Mip Maps”會為同一張紋理創建出很多不同大小的小紋理,構成一個紋理金字塔。而在遊戲中可以根據距離物體的遠近,來動態選擇使用哪一個紋理。

“Max Size”決定了紋理的長寬值,如果我們使用的紋理本身超過了這個最大值,Unity會對其進行縮小來滿足這個條件。

“Format”負責紋理使用的壓縮模式。通常選擇這種自動模式就可以了,Unity會負責根據不同的平臺來選擇合適的壓縮模式。而對於GUI型別的紋理,我們可以根據對畫質的要求來選擇是否進行壓縮

縮放

在考慮效能和畫面的平衡下,我們需要對特定機器的解析度進行放縮。
在Unity中設定螢幕解析度可以直接呼叫Screen.SetResolution

以上,就是我這一週關於遊戲優化的學習內容,我認為這是很有用的,接下來就可以開始專案系統的製作了。