(二)unity中的渲染優化技術——————(減少需要處理的頂點和片元數目)

一、減少需要處理的頂點數目

頂點數目同樣有可能成爲GPU的性能瓶頸,下面給出3個常用的頂點優化策略。

1.1優化幾何體

建模時儘可能減少模型中三角面片的數目,一些對於模型沒有影響、或是肉眼非常難察覺到區別的頂點都要儘可能去掉。美術人員往往需要優化網格結構。很多三維軟件都有相應的優化選項,可以自動優化網格結構。

在unity渲染統計窗口中可以查看到渲染當前幀需要的三角面片數目和頂點數目。需要注意的是,unity中顯示的數目往往要多於建模軟件裏顯示的頂點數,通常unity中顯示的數目要大很多,其實這是因爲在不同角度上計算的,都有各自的道理,但我們真正應該關心的是unity裏顯示的數目。

簡單解釋下造成這種不同的原因,三維軟件更多地是站在我們人類的角度理解頂點的,即組成幾何體的每一個點就是一個單獨的點。而unity是站在GPU的角度上去計算頂點數的。在GPU看來,有時需要把一個頂點拆分成兩個或更多的頂點。這種頂點一分爲多的原因主要有兩個:一是爲了分離紋理座標,另一個是爲了產生平滑的邊界。它們的本質,其實都是因爲對於GPU來說,頂點每一個屬性和頂點之間必須是一對一的關係。而分離紋理座標,是因爲建模時一個頂點的紋理座標有多個。例如對於一個立方體,它的6個面之間雖然使用了一些相同的點,但在不同面上,同一個頂點的紋理座標可能並不相同。對於GPU來說,這是不可理解的,因此他必須把這個頂點拆分成多個具有不同紋理座標的頂點。而平滑邊界也是類似,不同的是,此時一個頂點可能會對應多個法線信息或切線信息,這通常是因爲我們要決定一個邊是一條硬邊還是一條平滑邊。

對於GPU來說,它本質上只關心有多少個頂點,因此儘可能減少頂點數目其實才是我們真正需要管線的事情,最後一條几何體優化建議:移除不必要的硬邊以及紋理銜接,避免邊界平滑和紋理分離

1.2模型的LOD技術

這種技術的原理是,當一個物體離攝像機很遠時,模型上的很多細節是無法被察覺到的,因此LOD允許當對象逐漸遠離攝像機時,減少模型上的面片數量,從而提高性能。

在unity中可以使用LOD Group組件來爲一個物體構建一個LOD,我們需要爲同一個對象準備多個包含不同細節程度的模型,然後把他們賦值給LOD Group組件中不同等級,unity就會自動判斷當前位置上需要使用哪個等級的模型

1.3遮擋剔除技術

遮擋剔除可以用來消除那些在其他物件後面看不到的物件,這意味着資源不會浪費在計算那些看不到的頂點上,進而提升性能。

我們需要把遮擋剔除和攝像機的視椎體剔除(Frustum Culling)區分開來。視椎體剔除只會剔除掉那些不在攝像機的視野範圍內的對象,但不會判斷視野中是否有物體被其他物體擋住。而遮擋剔除會使用一個虛擬的攝像機來遍歷場景,從而構建一個潛在可見的對象幾何的層級結構。在運行時刻,每個攝像機將會使用這個數據來識別哪些物體是可見的,而哪些物體被其他物體擋住不可見,使用遮擋剔除技術,不僅可以減少處理的頂點數目,還可以減少overdraw,提高遊戲性能。

模型的LOD技術和遮擋剔除技術可以同時減少CPU和GPU的負荷。CPU可以提交更少的draw call,而GPU需要處理的頂點和片元數目也減少了。

二、減少需要處理的片元數目

另一個造成GPU瓶頸的是需要處理過多的片元,這部分優化的重點在於減少overdraw,簡單來說,overdraw指的就是同一個像素被繪製了多次。

unity還提供了查看overdraw的視圖,我們可以在Scene視圖左上方下拉菜單選中overdraw即可:

實際上,這裏的視圖只是提供了查看物體相同遮擋的層數,並不是真正的最終屏幕繪製的overdraw。也就是說,可以理解爲它顯示的是,如果沒有使用任何深度測試和其他優化策略時的overdraw。這種視圖是通過把所有對象都渲染成一個透明的輪廓,通過查看透明顏色的累計程度,來判斷物體之間的遮擋。當然我們可以使用一些錯誤來防止這種最壞情況的出現。

2.1控制繪製順序

爲了最大限度地避免overdraw,一個重要的優化策略就是控制繪製順序。由於深度測試的存在,如果我們可以保證物體都是從前往後繪製的,那麼就可以很大程度上減少overdraw,這是因爲在後面繪製的物體由於無法通過深度測試,因此就不會在進行後面的渲染處理。

在unity中,那些渲染隊列數目小於2500(如“Background” “Geometry”和“AlphaTest”)的對象都被認爲是不透明(opaque)的物體,這些物體總體上是從前往後繪製的,而使用其他的隊列(如“Transparent” “Overlay”等)的物體,則是從後往前繪製的。這意味着我們可以儘可能地把物體的隊列設置爲不透明物體的渲染隊列,而儘量避免使用半透明隊列

而且我們還可以充分利用unity的渲染隊列來控制繪製順序。例如在第一人稱射擊遊戲中,對於遊戲中的主要人物角色來說,他們使用的shader往往比較複雜,但是由於他們通常會擋住屏幕的很大一部分區域,因此我們可以先繪製它們(使用更小的渲染隊列)。而對於一些地方角色,它們通常會出現在各種掩體後面,因此我們在所有常規的不透明物體後面渲染它們(使用更大的渲染隊列)。而對於天空盒子來說,它幾乎覆蓋了所有的像素,而且我們知道它永遠會出現在所有物體的後面,因此它的隊列可以設置爲“Geometry+1”。這樣就可以保證不會因爲它而造成overdraw。

這些排序的思想往往可以節省許多渲染時間。

2.2時刻警惕透明物體

對於半透明對象來說,由於沒有開啓深度寫入,因此想要得到正確的渲染效果,就必須從後往前渲染。這意味着,半透明物體幾乎一定會造成overdraw。如果如果不注意,在一些機器上可能會造成嚴重的性能下降。例如對於GUI對象來說,他們大多被設置成了半透明,如果屏幕中GUI佔據的比例太多,而主相機又沒有進行調整而是投影整個屏幕,那麼GUI就會造成大量overdraw。

因此如果場景中包含了大面積的半透明對象,或者很多層相互覆蓋的半透明對象(即便他們每個的面積可能都不大),或者是透明的粒子效果,在移動設備上也會造成大量的overdraw,這應該是避免的。

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

在移動平臺上,透明度測試也會影響遊戲性能,雖然透明度測試沒有關閉深度寫入,但由於它的實現使用了discard或clip操作,而這些操作會導致一些硬件化的優化策略失效。例如PowerVR使用基於瓦片的延遲渲染技術,爲了減少overdraw它會在調用片元着色器前就判斷哪些瓦片被真正渲染的。但是由於透明度測試在片元着色器中使用了discard函數改變了片元是否被渲染的結果,因此就無法使用上述優化策略了。也就是說只有在執行了所有的片元着色器後,GPU才知道哪些片元被真正渲染到屏幕上了。這樣原先可以減少overdraw的優化就都無效了。這種時候使用透明度混合的性能往往比使用透明度測試更好。

2.3減少實時光照和陰影

實時光照對於移動平臺是一種非常昂貴的操作。如果場景中包含了過多的點光源,並且使用了多個Pass的shader,那麼很可能會造成性能下降。例如一個場景如果包含了3個逐像素的點光源,而且使用了逐像素的shader,那麼很有可能將draw call數目(CPU的瓶頸)提高3倍,同時也會增加overdraw(GPU的瓶頸)。這是因爲對於逐像素的光源來說,被這些光源照亮的物體需要被再渲染一次。更糟的是,無論是靜態批處理還是動態批處理,對於這種額外的處理逐像素光源的Pass都無法進行批處理,也就是說,他們會中斷批處理。

當然,遊戲場景還是需要光照才能得到出色的畫面效果。許多移動平臺的遊戲往往使用了烘焙技術,把光照提前烘焙到一張光照紋理(lightmap)中,然後在運行時刻只需要根據紋理採樣得到光照結果即可。另一個模擬光源的方法是使用God Ray。場景中很多小型光源的效果都是靠這種方法模擬的,他們一般並不是真正的光源,很多情況是通過透明紋理模擬得到的。在移動平臺上,一個物體使用的逐像素光源數目應該小於1(不包括平行光),如果一定要使用更多實時光,可以選擇逐頂點光照來代替。

有些遊戲角色看起來使用了非常複雜高級的光照計算,但這實際上是優化後的結果,開發者把複雜的光照計算存儲到一張查找紋理(lookup texture,查找表,LUT)中,然後在運行時刻,我們只需要使用光源方向、視角方向、法線方向等參數,對LUT採樣得到光照結果即可。使用這樣的查找紋理,不僅可以讓我們使用更出色的光照模型,例如更復雜的BRDF模型,還可以利用查找紋理的大小來進一步優化性能,例如主要角色可以使用更大分辨率的LUT,而一些NPC就使用較小的LUT。他們往往會開發一個LUT烘焙工具,來幫助美術人員快速調整光照模型,並把結果存儲到LUT中。

實時陰影同樣是一個非常消耗性能的效果,不僅是CPU需要提交更多的draw call,GPU也需要進行更多的處理。因此我們應該儘量減少實時陰影,例如使用烘焙把靜態物體的陰影信息存儲到光照紋理中,而只對場景中的動態物體使用適當的實時陰影。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章