《Unity預計算即時GI》笔记:二、光照图

Posted by 蔡华的博客 on February 22, 2017

说明

光照图

什么是光照图

  • 光照图在第三章中有如下的定义,读起来很是费解。

一個光照圖(Chart)是表示一個光照貼圖的區域,用來映射場景物件的光照貼圖UV。你可以想像是能影響物件的一張小磁磚圖,一張光照圖由兩部分組成:輻照度(照明)和方向性(主要光線方向編碼)。

  • 到了第六章又有如下讲解,读完之后我更加费解了,所以暂时搁置吧。

產生光照圖(Charts)的目的主要是用來包住靜態網格著色器(Static Mesh Renderer)的UV貼圖座標。

如何生成

一個物件所需要的光照圖數量主要是看物件有多少片UV shell需要拆解。所謂拆UV的學問就是保持幾何面上貼圖像素扭曲度和所需的Shell數量之間的平衡。

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

  • 这个部分要结合原文的图来看,从这个部分的文章中可以看到,在模型导入时决定了它需要几个光照图,而場景裡面有大量的光照圖可能會是PRGI耗時的原因之一

  • 从上下文的介绍来看,光照图是光照贴图的映射,记录了实时计算的结果,当计算光照时,需要从中提取信息。

  • 看看下列範例圖:

image

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

image

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

image

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

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

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

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

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

如何查看已经生成的光照图

  • 首先需要生成LightingData数据,将场景中的模型勾选static,然后在light window中点击build(也可以选择Auto) 。
  • 场景窗口中选择,UV Charts模式會把場景裡不同光照圖用不同顏色表示 image

如何减少光照图

  • 需要对以下几个参数进行设置

image

  • 先放一下原模型的图,后续会有大量的结果图。

image

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

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

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

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

  • 这个属性应该是用于控制拼接UV图的,值越大就会使得原本一些间距比较大的shell能够进行合并,这样就可以减少光照图的数量。
  • 做了一个简单的测试,分别设置为0.1、0.5、0.8。明显可以看出来,当数值很小的时候会分出更多的光照图,而且从浅蓝色线条可以看出是模型的边。

image

Auto UV Max Distance:0.1 / Auto UV Max Angle:89

image

Auto UV Max Distance:0.5 / Auto UV Max Angle:89

image

Auto UV Max Distance:0.8 / Auto UV Max Angle:89

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

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

  • 基本原理和Auto UV Max Distance一直,更大的数值使得更多比较扭曲的UV Shell能够合并,弊端也说的比较明确。

  • 以下仍旧是一组对比图

image Auto UV Max Distance:0.5 / Auto UV Max Angle:50

image

Auto UV Max Distance:0.5 / Auto UV Max Angle:89

image

Auto UV Max Distance:0.5 / Auto UV Max Angle:120

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和光照圖並保持可以接受的貼圖拉扯範圍。

  • 感觉大多数时间是不需要这个东西的,即使unity自己UI展开的不好如果不伤大雅也可以不用。

  • 生成的图放到下面进行对比

Ignore Normals(忽略法線)

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

  • 信息量略大,首先为了减少Draw Call时三角形面数过多,unity在导入网格是进行拆分,自然这就导致了产生一些多余的UV Shell。

Ignore Normals選項可以防止模型在匯入時光照圖被拆開

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

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

  • 挺好,只是为了PRGI,正常的网格还是会被拆分已做别的用途。

  • 最后放下结果对比

image

Auto UV Max Distance:0.5 / Auto UV Max Angle:89 / 使用模型UV

image

Auto UV Max Distance:0.5 / Auto UV Max Angle:89

image

Auto UV Max Distance:0.5 / Auto UV Max Angle:89 / 忽略法线

  • 目测这个模型按照默认设置效果就挺好的。
  • 后续讲了一些实际的操作,还是自己读文章吧。

光照图总结

  • 目前来看整个PRGI的大头在于光照图,而如何减少光照图是重中之重。
  • 参数虽然都已经很清楚,而且UV Charts中可以看到具体的效果。不过,在多个模型的场景中每个模型做优化也是个很费时间的事情。