2016年12月26日 星期一

Unity預計算即時GI - 6.拆解與減少光照圖

原文
翻譯:Kelvin Lo

版本:5.5 難度:中等

上一章我們已經排除掉一些不需要計算即時光照的物件,現在可以開始幫剩下的光照圖繼續做瘦身工作。

產生光照圖(Charts)的目的主要是用來包住靜態網格著色器(Static Mesh Renderer)的UV貼圖座標。一個物件所需要的光照圖數量主要是看物件有多少片UV shell需要拆解。所謂拆UV的學問就是保持幾何面上貼圖像素扭曲度和所需的Shell數量之間的平衡。

一般來說Unity的拆解演算法能拆出不錯的結果,但有時候我們會需要手動調些設定,因此是有必要了解一下自動拆解功能背後的運作原理。

看看下列範例圖:


這樣的UV拆解不會變形,但需要多張UV shells


用單一UV shell所產生的結果,但貼圖變形很嚴重


比較理想的結果,單一UV shell且貼圖沒有變形

從上面我們可以看到三個拆UV不同的例子

從第一張圖裡我們可以看到做為貼圖的棋盤格圖案像磁磚一樣保持比例的貼在方塊表面上並沒有變形。試想如果這個棋盤圖案是一個光照貼圖(一個打在物件上的光照圖像),我們會得到一個視覺上看起來沒有問題的結果,只是會需要耗費六個UV shells。那就表示待會用Unity PRGI計算的時候也會產生六張光照圖,不管條件如何,每個光照圖最少都需要4x4個貼圖像素來表示,還沒考慮解析度之前最少就會耗掉96個像素。

在第二張圖裡我們會遇到不同的狀況,物件的UV貼圖座標只用一個UV shell就涵蓋所有範圍,雖然這樣所產生的光照圖最少,但視覺效果卻不是我們要的。我們會看到物件表面上的貼圖歪掉了,貼圖在UV空間裡也相互重疊,代表如果這是一張光照貼圖,物件一面的光照可能會錯投到相反面上。很明顯的這種拆法是有問題的。

第三張圖的結果比較理想,棋盤沒有扭曲,磁磚比例也保持正方形。而且還成功用一張UV shell覆蓋物體的所有面。屆時透過連接或縫合對應在模型上的邊緣來把位置合上。
如果用技術的邏輯來看,整個過程做了哪些事情呢? 首先,我們會將UV圖用正交投影(Orthogonal Projection)在物件上來產生獨立的Shell,然後我們就會分析哪些Shell和物件的邊緣有相連關係,一旦我們找到了這些邊緣,我們就會把UV shell的內容移進去並和相鄰的Shell縫合起來。

可視化的光照圖



在開始優化我們的拆解流程和光照圖之前,我們需要有個方法從編輯器來檢視它們。光照圖是在網格導入流程的一個拆解階段(Unwrapping stage)被產生出來的。對於PRGI來說,這些光照圖會在預計算裡的幾何階段(Geometry stage)被打包到不同的圖集(Atlas)裡,這是為了確保它們不會相互重疊。一旦預計算的幾何階段完成之後就會產生可視化數據,我們就能預覽光照圖。

如果你用版本控制(Version control)管理,請注意,這個預覽資料只會儲存在本機,所以在開始檢查之前要執行預計算一次。

UV Charts模式會把場景裡不同光照圖用不同顏色表示,光照貼圖解析度會用棋盤格表示疊在上面

要快速檢視光照圖可以在場景視窗切換UV Charts繪製模式


  • 從場景視角(Scene View)左上方的Draw mode下拉選單找到UV Charts。

在這個模式下,光照圖會用不同的顏色和一個表示解析度的棋盤圖疊在一起,如果自動烘焙模式是啟用的(Window > Lighting > Auto),也會自動計算拆解變數的變動並更新在場景視窗上。


Charting模式的預覽視窗會用不同的顏色的格子表示光照圖,並用淺藍色的線表示UV貼圖。

當場景複雜的時候從場景視窗有可能會漏看光照圖。如果從Lighting視窗用預覽模式的話,我們就可以針對查看單一物件查看它所有使用的光照圖。這樣可以幫我們更精準的評估這些物件拆解結果,有助於降低光照圖的數量。

  • 打開Lighting介面(Window > Lighting),選擇Object頁籤。
  • 從Hierarchy視窗選擇你想檢視的物件。
  • Lighting視窗裡的預覽窗格,從最上面的下拉式選單選擇Charting模式。

物件耗用的光照圖數量會以不同顏色的方塊疊在對應的淺藍色UV座標上。

拆解參數說明


有幾個設定有助於拆UV的優化,所有的設定都是針對單一物件,我們可以透過下列流程來設定:

  • 開啟Lighting介面(Window > Lighting) 並選擇Object頁籤
  • 從Hierarchy視窗裡選擇你要設定的物件

Auto UV Max Distance(自動最大UV距離)

Unity的拆解演算法會嘗試把不同Shell做調整將UV邊緣拼接在一起來簡化UV貼圖。當Shell放入後還能保持在Auto UV Max Distance規定的範圍內時才會被考慮進來。這個範圍是用Unity的世界空間座標來定義的,在我們的範例裡是1米。
Auto UV Max Distance設定可以從Lighting視窗裡的Object頁籤找到

在許多情況下,預設的0.5就能給出不錯的結果,但對於具有大面積的特大物件可能要提高這個值來防止本來應該被縫合的UV圖被演算法排除在外。

增加這個值通常會讓物件所需的光照圖數量減少,而降低這個值通常有助於解決貼圖像素被拉扯的問題,當然就會需要產生更多的光照圖來覆蓋。改變這個值後你可以透過檢視場景UV Charts繪製模式,從覆蓋的棋盤圖來評估並實驗出一個最好的平衡點。

Auto UV Max Angle(自動最大UV角度)

拆UV的計算當然也會考慮到相鄰Shell的角度,Auto UV Max Angle定義相鄰面共享邊緣允許的最大角度,並用內角來計算如果背面的角度大於這個值,就會排除縫合這個UV Shell。
Auto UV Max Angle設定可以從Lighting視窗裡的Object頁籤找到

提高這個值會讓Unity的演算法更容易組合UV圖,這也表示能透過這個功能來降低單一物件的光照圖數量,但是如果設的太寬鬆有時候會出現貼圖被拉扯的狀況。反之降低這個值會造成演算法不好把相鄰的UV排一起,雖然拉扯的情況會降低但是會產生更多光照圖。相同,檢視UV Charts繪製模式裡的棋盤圖並試出一個最適合的值。

Preserve UVs(保留UV)

在某些情況下,自動拆UV如果無法獲得理想結果,可能會產生過多的光照圖或是貼圖失真(GI Charts繪製模式可以做拉扯檢查)。在這種情況下可能需要在模型的UV01通道手動建立UV。這必須要在其他工具完成。

如果這種情況發生,我們可以在Preserve UVs選項讓Unity演算法強制採用模型UV01通道指定的UV Shell。
當需要手動保持UV圖時,Preserve UVs選項很有用

要注意的是這些Shell會被重新打包來節省光照貼圖空間,它們會被單獨解開保留,而不是只有把在光照貼圖內的座標記錄起來而已。

使用這個功能時必須小心,當指定的UV貼圖包含著大量的UV shells時,這個功能可能會讓預計算的時間拉長,因為Unity的拆解演算法被跳過,手動保留的UV Shells到時候會全餵給預計算流程。記住,最好的結果是儘可能的降低UV shells和光照圖並保持可以接受的貼圖拉扯範圍。

Ignore Normals(忽略法線)

在某些情況下,網格匯入器可能會拆開幾何圖形,這也會影響到光照圖的數量。例如,如果有個網格有非常多的三角面,Unity可以為了效能把它分割成幾個獨立的子網格。通常這麼做是為了符合特定硬體需求,例如為了減少每個Draw Call所需要呼叫的三角面數量。分割通常會發生在相鄰的網格面之間法向角度有大變化的區域,比如銳角邊(hard edges)。這樣的拆分網格方式會在模型導入流程時執行,在這個過程中,UV Shell也可能會被拆分開來放到不同的光照圖,造成額外的光照圖消耗。
Ignore Normals選項可以防止模型在匯入時光照圖被拆開

有時候放著上述的問題不管不太值得,得到的結果讓光照圖數量增加拉長了預計算的時間,還有可能在照明的接縫造成不必要的視覺假象。在這樣的情況下,啟用Ignore Normals選項有助於防止光照圖在預計算的時候被分割開來。

請注意,這個選項只有對預計算即時光照(PRGI)有影響,物件被拆分的網格仍然會被保留以用在其他用途。

大場景中更快的迭代


複雜的場景可能包含著上百或上千的靜態物件,幫這些物件計算光照圖集可能會導致預計算變很慢,對我們在場景的迭代速度產生負面影響。

當你在測試研究上述設定時,有時候把物件換到空場景是很有幫助的,這樣可以用最小的預計算時間來快速迭代。測好設定之後可以把設定貼回原本場景裡其他的同類型物件,這樣可以節省時間。

  • 打開範例裡的LightingTutorialStart場景
  • 從Hierarchy介面裡選擇HouseBig02物件,他們在Environment > Structures > Houses。
  • 按Ctrl + C複製這個物件(Mac是Cmd +C)
  • 按Ctrl+N建立一個新的場景(Mac是Cmd+N)
  • 可能會有提示問你是否要存檔,選Yes可存檔,選No可不存檔。
  • 在新的空場景裡按Ctrl+V把房子貼上(Mac是Cmd+V)
  • 打開Lighting介面(Window > Lighting)選擇Scene頁籤
  • 確保最下面的Auto有打勾
  • 選擇Object頁籤
  • 最上面左邊的下拉式選單選擇Charting
  • 拉大預覽視窗的區域來查看物件拆解的狀況

調整拆解設定,優化預計算時間


當調整拆解設定時,最好的結果是找到能產生最少光照圖與最低失真度的參數組合。請記住,當啟用UV Charts繪製模式時,失真的程度能從場景裡的棋盤圖拉扯狀況來評估。
棋盤圖案用來可視化光照貼圖的分佈,這張圖呈現出棋盤圖和模型的一致性,代表失真度低


棋盤圖在模型表面被拉扯表示和光照圖的分配不一致

接下來我們會用教學範例來實現我們所學關於UV拆解與優化預計算時間的方法。

  • 開啟範例裡的LightingTutorialStart場景
  • 從Hierarchy介面裡選擇HouseBig02物件(Environment > Structures > Houses)
  • 打開Lighting介面(Window > Lighting)並選擇Object頁籤
  • 從上方左邊的下拉式功能表選擇Charting
  • 展開預覽視窗,注意這裡顯示了多少UV shells與對應顏色的光照圖數量。
上圖表示用Charting預覽檢視預設設定下的HouseBig02物件,這個結果還有很大的優化的空間。

HouseBig02是場景裡一個複雜的物件,用了許多光照圖來詮釋,但還有空間調整設定來減少光照圖的數量。
拆解設定畫面

沒有一個固定尺寸能符合全部狀況,Unity的拆解演算法會基於預設值適當的決定,但是透過一些經驗的累積,可以微調出更好的結果。

  • 從Hierarchy視窗裡選擇HouseBig02物件
  • 開啟Lighting介面(Window > Lighting) 選擇Object頁籤
  • 調整Auto UV Max Distance為0.1

接下來預計算會開始啟動,經過短暫的計算時間後,我們可以從預覽視窗看到光照圖數量明顯增加許多,檢查場景視窗可以看到貼圖只有一點拉扯,這是好現象。但我們無法接受多了這麼多光照圖。因為光照圖一多代表預計算時間會變長,效能也會降低。

  • 從Hierarchy視窗再次點選HouseBig02
  • 開啟Lighting介面(Window > Lighting) 選擇Object頁籤
  • 調整Auto UV Max Distance為10

現在問題應該會反過來,光照圖的數量會降低,但你可以從UV Charts繪製模式裡看到,光照圖拉扯的問題會變得很嚴重。
值太高可能會導致UV會被拉扯到

Unity會嘗試把UV Shells合併來最小化光照圖的數量,當兩個Shell要合併時會把這個值一併列入考慮,如果兩個Shell的距離大於這個值,就不會被合併。

所以當我們把這個值調低時,被合併的UV Shell就變少。這代表最後會產生很多單獨的光照圖。而當我們調高這個值時,距離很遠的UV Shell都會被考慮合併,就會產生比較少的光照圖,但相對的也會讓光照圖容易產生扭曲。

對於大物件有時候可能需要調高這個值來確保整個網格面積都涵蓋到,相反的如果是小物件也可以調低這個值來產生更好的結果。

以我們的範例HouseBig02來說,設定0.8的Auto UV Max Distance是一個好的平衡點。

  • 從Hierarchy視窗再次點選HouseBig02
  • 開啟Lighting介面(Window > Lighting) 選擇Object頁籤
  • 調整Auto UV Max Distance為0.8
設定為0.8得到一個不錯的結果。但我們還能繼續改善

現在我們來看看Auto UV Max Angle參數,和距離一樣,這個值影響著Unity拆解演算法的結果,演算法除了會評估距離之外也會評估相鄰網格之間的角度,角度低於這個值才會被合併。

較小的角度代表更低的通過率,更少的UV Shell被合併,以及更多的光照圖產生。相反,較大的角度代表演算法能容忍的角度更大,更多的UV Shell能被合併。和距離的情況一樣,結果會減少光照圖的數量,但是會有變形的問題。

  • 從Hierarchy視窗再次點選HouseBig02
  • 開啟Lighting介面(Window > Lighting) 選擇Object頁籤
  • 設定Auto UV Max Angle為0

從預覽視窗能看到所產生的光照圖高的不像話,那是因為我們只允許0或更小的角度才考慮合併,這代表沒有UV Shell會被合併,每個都會獨立產生光照圖。
太小的角度設定會造成產生過多的光照圖

接下來我們來試試看把角度調大:

  • 從Hierarchy視窗再次點選HouseBig02
  • 開啟Lighting介面(Window > Lighting) 選擇Object頁籤
  • 慢慢調高Auto UV Max Angle,觀察預覽視窗裡面的結果

可想而知,光照圖的數量會隨著角度增加而減少,這是因為更多的UV Shell允許被合併,UV Shell數量降低光照圖就變少。

加大角度有助於減少光照圖,尤其是在具有圓形表面的物體上

以這個案例來說,將這個值設為93對於HouseBig02可以得到最好的結果。

  • 從Hierarchy視窗再次點選HouseBig02
  • 開啟Lighting介面(Window > Lighting) 選擇Object頁籤
  • 設定Auto UV Max Angle為93

注意在計算之後減少了多少光照圖
從Charting預覽看到優化之後的HouseBig02

到這裡你可以把這些測試出來的設定帶回原本的場景,步驟有點複雜請注意:

  • 從Hierarchy視窗再次點選HouseBig02
  • 從Inspector視窗找到Mesh Renderer元件,點選上面的齒輪按鈕後選擇Copy Component。
  • 重新開啟LightingTutorialStart場景
  • 從Hierarchy視窗找到原本的HouseBig02的目錄
  • 按住Ctrl(Mac按住Cmd)然後把所有的HouseBig02一一點選起來。
  • 開啟Lighting介面(Window > Lighting) 選擇Object頁籤
  • 點一下齒輪,選擇Paste Component Values,剛剛調好的設定就會反映到全部選起來的HouseBig02物件
用Copy Component是一個簡單的管道來複製設定到另外一個場景

當必須針對場景好幾百個物件調整設定時,這樣的操作能更節省來把時間花在其他優化上

拆解設定:實例(pre-instance)還是預製(pre-Prefab)好?


拆解設定可以存在預制物件(Prefab)裡,只要把這些帶有Static Mesh Renderer元件的物件存成Prefab即可,或是直接把設定指給場景裡的物件也行。

如果拆解設定是貼在一個經過Prefab實例化(instance)的物件,那麼會蓋掉原本在Prefab裡的設定,在某些情況下能幫場景做些不同的變化。

做一個預設Prefab用來作為拆UV和光照設定的基礎物件是很不錯的,如果Prefab需要常被實例化,這麼做就能節省一些設定的時間。

另一方面來說,這種做法蠻適合基於場景不同的物件配置來指定拆解設定,例如,在離玩家近的區域內看到的預制物件可以設定更好品質,反而如果物件離很遠,那用同樣的設定就沒甚麼意義,這裡應該降低光照貼圖品質,並積極的降低光照圖的數量。

可以設定一個符合大部分的狀況的設定,然後在需要的情況下去覆蓋這些設定,在本次教學裡,我們會針對每個實例物件來設定。

幫場景指定拆解設定


現在是時候將所學應用到這個教學場景。有系統的執行應該不會花太久的時間來設定。

  • 開啟LightingTutorialStart場景
  • 從Hierarchy視窗Environment > Structures 找到最上面的物件
  • 把這個物件複製到一個空場景

到這裡我們應該用我們所學,嘗試各種不同的值,善用UV Charts繪製模式和Charting模式做比對,找到一個平衡的設定。

如果你不知道如何設定,LightingTutorialOptimal這個範例場景可以當作是一個很好的參考,雖然大部分的情況下用預設值就可以得到很好的結果。

  • 嘗試使用不同的值來找出一個最低光照圖數量和失真度的平衡點
  • 複製設定,回到LightTutorialStart場景把設定貼回去所有的相同物件。選擇多個物件後能一次把設定貼上
  • 對Hierarchy視窗裡Structures目錄下所有的單獨命名的物件重複此步驟
一旦所有在Structures目錄下的物件都有了優化設定,可以轉到Rocks目錄下處理剩下的靜態物件。以這種手動循環設定好場景裡所有的靜態物件,確保有更好的迭代流程和更好的執行效能。


---------------------------------------------------------------------------------

Unity預計算即時GI全文超連結
Unity預計算即時GI - 9.總結
Unity預計算即時GI - 8.微調光照參數
Unity預計算即時GI - 7.了解叢集
Unity預計算即時GI - 6.拆解與減少光照圖
Unity預計算即時GI - 5.光照探測
Unity預計算即時GI - 4.開始預計算
Unity預計算即時GI - 3.了解光照圖
Unity預計算即時GI - 2.即時解析度
Unity預計算即時GI - 1.介紹


沒有留言:

張貼留言

著作人

網誌存檔