- 前言
在計算環境反射時,最常使用的就是 Cubemap。
圖片來源: Unity Manual
Cubemap 是由六張圖片對應六個方向所組成,
這對於 mobile 來說負擔太大,很容易造成效能瓶頸。
因此,本篇介紹一個較輕量的作法來實現環境反射,
此方法叫 Dual Paraboloid Environment Mapping。
- 原理
先來看一個二元的數學方程式
這時透過觀察可以發現:當 x^2 + y^2 ≤ 1, 則 0 ≤ f(x,y)。
在上述的條件下,取 F(x,y) 上的任一點 P,
P 的座標可以記為 (x, y, f(x,y))。
在 P 點上,分別對 x 軸和 y 軸作微分,可以得到 P 點上的兩個切線向量。
接著,對 Tx 和 Ty 做外積,可以得到 P 點上的法向量 N = (x,y,1)。
這時取一條從原點到 P 點的向量 P',
計算 P' 相對於 N 的反射向量 R 。
R 的計算可以透過反射公式求得。
其中,上述所有向量都必須為單位向量。
因此,首先正規化向量 P' 和 N。
得到兩個正規化向量後,帶入反射公式,求得反射向量 R。
可以得知,反射向量為一個固定值(0,0,1)。
從上述的證明可以得到兩個重點
- 平面 f(x,y) 上任何一點的法向量 N = (x,y,1),因為其 Z 軸為一個常數值,所以 N 可以視為一個二維變數。
- 從原點開始的任何一個向量 P',和平面 f(x,y) 接觸後的反射向量為一個固定值(0,0,1)。
這代表著我可以將一個三維向量 P' 在 Cubemap 取得的顏色資料 D,
透過計算向量 P' 和平面 f(x,y) 交接處的法向量 N,
將顏色資料 D 儲存在一個2維陣列內。
而法向量 N 的計算就透過 P' 和固定反射向量 R 來求得。
但回頭看看平面方程式,為了方便說明我只顯示 X-Z 平面的形狀
這個平面只包含了上半部(+Z),
勢必要提供一個下半部(-Z)的二元方程式,才能完整獲得 Cubemap 所有範圍資料。
因此透過此方法,可以將一個 6張2維貼圖的資料,只用 2張2維貼圖儲存,
大大的減少資源需求。
- Unity 實作
在實作範例中,我示範如何將一個使用 Cubemap 的 skybox,轉化成兩張 2維貼圖。
Dual Paraboloid map 一般用在即時的環境映射(事實上,我參考的文獻也是此種做法),
但一般 mobile 很少做這種計算,且兩者做法類似,
因此我在這裡示範 off-line 的 cubemap 轉換,若對 real-time 的環境映射有興趣,
可以參考我在文章最後列出的參考項目。
首先,在 Scene 裡面產生一個 Sphere 模型,
然後把攝影機設定在 Sphere 的原點為0,並設定 Clear Flags 為 Solid Color,顏色指定黑色
(在範例中,我是將畫面分成 +Z 和 -Z 兩個方向,所以攝影機的旋轉值全部設為 0)

接著,將 Sphere 掛上下面 Shader,並指定要轉換的 Cubemap
畫面變成
將輸出的畫面儲存。
接著把攝影機繞 Y 軸轉 180度,重複上述步驟,會得到下面結果

如此就完成了 Dual Paraboloid Environment mapping。
最後在附上 Dual Paraboloid Environment mapping 的 skybox shader。
- 結論
本章節只討論 Dual Paraboloid Environment mapping 的其中一個應用,
就如同文章一開始所提到的, 一般常見的用法是用在 real-time 環境反射。
但兩者基本上做法是一樣,有興趣的人可以參考後面的參考連結,
修改上面提供的 shader 試試。
- References
沒有留言:
張貼留言