UnitySahder入門精要筆記---Unity中的渲染優化技術
Unity中的渲染優化技術筆記
最近一直在研究關於UnityShader的知識,由於是小白入門,對於相關的文章比較感興趣,而對於UnitySahder入門精要的閱讀和練習,也確實收益匪淺,也因此想著寫下一些讀書筆記來做一些記錄以備自己以後翻看查閱,同時也希望為有需要的同學提供些許幫助吧,這一篇的筆記主要是記錄一些自己在對於Unity中渲染優化技術一章的理解和練習吧,如有不對的地方,請大家諒解,也歡迎指正,從而學習到更多的知識!
1.移動平臺特點
對於遊戲的開發和效能優化永遠離不開的兩個話題就是CPU和GPU的優化,通俗一些的理解就是CPU的幀率保證,玩遊戲不卡幀,GPU保證解析度等相關處理,畫面精緻遊戲感強,同時又由於手遊的便攜性和普遍性,相比於端遊的開發,手遊的開發更易於投入市場,但是也由於手機的硬體配置和PC機存在很大的區別,對於效能的優化來說,手遊的優化要求也相對較多一些,在這裡對於渲染效能的優化也同樣適用於移動平臺手遊。
2.影響效能的因素分析
2.1 影響因素
上文中已經提到了CPU和GPU兩個方面對於遊戲效能的影響,同時頻寬也是會造成一定的影響的,因此下文中也主要以這幾個方面來介紹:
CPU方面
1)過多的draw call (對於draw call的研究在這裡就不多解析了,有時間的話會專 門把draw call的研究寫出來的)
2)複雜的指令碼和物理模擬
GPU方面
1)頂點處理
a.過多的頂點
b.過多的逐頂點計算
2)片元處理
a.過多的片元(有解析度和overdraw兩種原因)
b.過多的逐片元計算
頻寬
1)使用了尺寸很大未壓縮的紋理
2)解析度過高的幀快取
2.2 效能優化技術簡要分析
CPU優化
使用批處理技術減少draw call數目
GPU優化
1)減少需要處理的頂點數目
a. 優化幾何體
b. 使用模型的LOD(Level of Detail)技術
c.使用遮擋剔除(Occlusion Culling)技術
2)減少需要處理的片元數目
a. 控制繪製順序
b.警惕透明物體
c.減少實時光照
3)減少計算複雜度
a.使用Shader的LOD技術
b.程式碼方面的優化
節省記憶體頻寬
1 ) 減少紋理大小
2)利用解析度縮放
3.減少draw call 數目
批處理的實現原理就是為了減少每一幀需要的draw call 數目,對於可以進行批處理的前提是使用同一個材質,使用同一個材質的物體,之間的不同只是頂點資料的差別,可以進行頂點資料的合併,再發送給GPU,完成一次批處理。
Unity3D支援兩種批處理方式,一種是動態批處理(Dynamic Batching),一種是靜態批處理(Static Batching)。
動態批處理:
優點:一切處理是Unity自動完成,不需要認為進行任何操作,場景中的物體可以進行任何移動。
缺點:限制條件比較多,很容易打破動態批處理規則,導致動態批處理失效
靜態批處理:
優點:自由度比較高,限制很少
缺點:佔用更多記憶體,經過靜態批處理的物體在場景中不可以再次移動,否則打破靜態批處理規則,不可進行靜態批處理了。
3.1 動態批處理
動態批處理不需要人為的去設定,Unity會自動進行整合,前提是這些模型共享的同一個材質,同時需要滿足一些條件,在這裡主要是對這些條件進行了總結:
能夠進行動態批處理的網格頂點屬性規模要小於900.例如,如果Shader中需要使用頂點位置、法線和紋理座標這3個頂點屬性,那麼想要讓模型能夠被動態批處理,它的頂點數目不能超過300。需要注意的是,這個數字未來有可能會發生變化,因此不要依賴這個資料。(注:經過筆者測試,在當前Unity2017,Unity2018版本中測試,對於頂點數目的限制未發生變化,所以說該限制條件依然有效)
一般來說,所有物件都需要使用同一個縮放尺度。一個例外的情況是,如果所有的物體都使用了不同的非統一縮放,那麼它們也是可以被動態批處理的。(注:該條件限制已經無效,經筆者在Unity2018中測試,不同的縮放尺度不影響動態批處理)
使用光照紋理的物體需要格外小心處理。這些物體需要額外的渲染引數,例如,在光照紋理上的索引、偏移量和縮放資訊等。因此,為了讓這些物體可以被動態批處理,我們需要保證它們指向光照紋理中的同一個位置。
多Pass的Shader會中斷批處理。在前向渲染中,我們有時需要使用額外的Pass來為模型新增更多的光照效果,但這樣一來模型就會被動態批處理了。
3.2 靜態批處理
實現原理: 只在執行開始階段,把需要進行靜態批處理的模型合併到一個新的網格結構中,這意味著這些模型不可以再執行時刻被移動。只需要一次的合併操作,任何大小且使用同一個材質的幾何模型都可適用,缺點在於,它往往需要佔用更多的記憶體來儲存合併後的幾何結構。這是因為,如果在靜態批處理前一些物體共享了相同的網格,那麼在記憶體中每一個物體都會對應一個該網格的複製品,即一個網格會變成多個網格再發送給GPU。如果遊戲中使用的這一類模型比較多,更會增加記憶體上的消耗。解決方法是要麼忍受,要麼在符合要求的情況下使用動態批處理,或者自己編寫批處理方法。
無論選擇使用動態批處理或者靜態批處理,這裡有一些小的建議:
1 儘可能使用靜態批處理,但得時間小心對記憶體的消耗,並且記住經過靜態批處理的物體不可以再被移動。
2 如果無法進行靜態批處理,而要使用動態批處理的話,小心上面提到的各種限制。
3 對於遊戲中的小道具,例如可以撿拾的金幣,可以使用動態批處理。
4 對於包含動畫的這類物體,我們無法全部使用靜態批處理,但其中如果有不動的部分,可以將這部分標識成“static”。
還有需要注意的一些地方:批處理是將多個模型變換到世界空間中進行合併,涉及到Shader中的一些基於模型空間的座標計算,可能會出現錯誤的結果, 解決方案:在shader的編寫中使用 DisableBatching 標籤來強制使用該Shader的材質不進行批處理,另一個需要注意的是使用半透明材質的物體通常需要使用嚴格的從後往前的繪製順序來保證透明度混合的正確性。對於這些物體,Unity會首先保證它們的繪製順序,再嘗試對它們進行批處理。這意味著,當繪製順序無法滿足時,批處理無法在這些物體上被成功應用。
4.減少需要處理的頂點專案
3種頂點優化策略
1.優化幾何體:主要的應用階段是美工階段,模型製作階段,在不影響模型造型基礎上儘可能減少頂點數目,從而減少模型的三角面數。
2.模型的LOD技術:原理是,當一個物體原理攝像機很遠時,模型的細節是無法被察覺的,因此可以減少模型上的面片數量,從而提高效能,也就是在Unity中使用LOD Group元件,進行模型等級隨距離的劃分,在這裡不做細緻的講解了,後續會做LOD的試驗。
3. 遮擋剔除技術:遮擋剔除技術就是在裁剪空間範圍內的被其他物體遮擋看不到的物體進行消除,不會對這些不被看到的物體進行渲染,提高效能,
(注:遮擋剔除(Occlusion Culling)和視錐體剔除(Frustum Culling))區分開來。視錐體剔除只會剔除掉那些不在攝像機的視野範圍內的物件,但不會判斷視野中是否有物體被其他物體擋住)
5.減少需要處理的片元數目
另一個造成GPU瓶頸的是需要處理過多的片元。這部分優化重點在於減少overdraw。簡單來說,overdraw 值得是同一個畫素被繪製了多次。主要是在3個方面避免overdraw。
1.控制繪製順序
由於深度測試的存在,如果我們可以保證物體都是從前往後繪製的,那麼就可以很大程度上減少overdraw。這是因為,在後面繪製的物體由於無法通過深度測試,因此,就不會再進行後面的渲染處理。
在Unity中,那些渲染佇列數目小於2500(如”Background” “Geometry” 和 “AlphaTest”)的物件都被認為是不透明物體,這些物體總體上是從前往後繪製的,而使用其他的佇列(如”Transparent” “Overlay”)的物體,則是從後往前繪製的。這意味著,我們可以儘可能地把物體的佇列設定為不透明物體的渲染佇列,而儘量避免使用半透明佇列。我們還可以充分利用Unity的渲染佇列來控制繪製順序。 例如將佇列設定”Geometry+1”這樣。
2.時刻警惕透明物體
對於半透明物體來說,本身並沒有開啟深度寫入,如果要得到正確的渲染效果,必須是從後往前渲染,也意味著,半透明物體幾乎一定會造成overdraw。例如GUI物件來說,它們大多數被設定為半透明物體,如果螢幕中GUI佔據的比例太多。而主攝像機又沒有進行調整而是投影整個螢幕,那麼GUI就會造成大量的overdraw。
如果場景中包含大面積半透明物件,或者多層相互覆蓋疊加的半透明物件,或者透明粒子效果,在移動裝置上都會造成大量overdraw,
因此,我們儘量減少視窗中GUI所佔的面積。也可以把GUI的繪製和三維場景的繪製交給不同的攝像機,而其中負責三維場景的攝像機的視角範圍儘量不要和GUI的相互重疊。
在移動平臺上,透明度測試也會影響遊戲效能。雖然透明度測試沒有關閉深度測試,但由於它的實現使用了discard或clip操作,而這些操作會導致一些硬體的優化策略失效。
3.減少實時光照和陰影
較為有效的方法以及當前普遍使用的方法就是使用了烘焙技術,將光照和陰影提前烘焙為一張光照紋理,當遊戲執行時,只是根據紋理取樣得到光照即可。
6.節省頻寬
1.減少紋理大小
在減少draw call數目中使用到的是一種將紋理整合成紋理圖集,根據uv取樣座標資訊來進行模型的不同紋理使用,紋理的長寬普遍為正方形,而且最好是2的整數冪,主要是這樣有利於很多優化策略最大有效值。
另外就是使用多級漸遠紋理技術,即mipmapping以及紋理壓縮。
2.利用解析度的縮放
過高的螢幕解析度也是造成效能下降的原因之一,尤其是對於很多低端手機,除了解析度高其他硬體條件並不盡如人意,這恰恰是遊戲效能的兩個瓶頸:過大的螢幕解析度和糟糕的GPU。因此,我們可能需要對於特定及其進行解析度的縮放。當然,這樣可能會造成遊戲效果的下降,但效能和畫面需要平衡。
7.減少計算複雜度
1.Shader的LOD技術
類似與模型的LOD技術,根據距離來控制Sahder的等級,原理:只有Shader 的LOD 值小於某個設定的值,這個Shader才會被使用,而使用了那些超過設定值的Shader 的物體將不會被渲染。
2.程式碼優化方面
對於實現遊戲效果時,存在著一定的特定運算,對於遊戲物件,頂點和畫素的計算的複雜程度排序是:物件數<頂點數<畫素數,因此儘量將允許的計算放在每個物件和逐頂點上。
對於程式碼的優化規則,有以下幾點建議:
1.在允許範圍內,使用低精度浮點值進行運算,減少不同精度之間的換算
2.儘量不使用全螢幕的屏幕後處理效果
3.儘可能不要使用分支語句和迴圈語句
4.儘可能避免使用類似sin、tan、pow、log等較為複雜的數學運算。使用查詢表來替代它。
5,儘可能不要使用discard操作,會影響某些硬體的優化(注:筆者對於這一點沒有測試,存在一定的疑問,待研究)
8. 小結
這是筆者第一次寫博文,因此也存在很多不足,以及對文章中的一些優化策略並沒有進行完全的試驗,有些仍然需要去摸索探究,後續有時間會繼續將這些測試試驗寫出來的,望諒解,同時也推薦有時間的話,可以讀一下《UnitySahder入門精要》這本書,書中的講解遠比筆者寫的更詳細全面,這裡的筆記也只是筆者自己的理解。
參考:
連結:
《UnitySahder入門精要》
Unity教程之再談Unity中的優化技術
https://www.cnblogs.com/gabo/p/4592194.html
---------------------
作者:ghaokl
來源:CSDN
原文:https://blog.csdn.net/ghaokl/article/details/86382117
版權宣告:本文為博主原創文章,轉載請附上博文連結!