2020年6月1日 星期一

3D 渲染基礎


  • 前言
3D渲染簡單來說,其實是將 3D物件投影到 2D平面的一個技術。

不論使用的 Graphic API 是 OpenGL 也好, 還是 DirectX ,都是做相同的運算。

本章節將討論空間轉換的基礎知識,及 Unity3D 內的特殊處置,

作為光照計算以外特殊運用的基礎 (ex.水面倒影、戰爭迷霧 etc. )。

  • 坐標系
空間轉換的計算雖然說基本相同,但 OpenGL 和 DirectX 間仍有細微的差異,

最明顯的差異就是使用的坐標系不同。


OpenGL 使用右手座標系, X 向右遞增,Y向上遞增、Z向後遞增。

DirectX  使用左手座標系, X 向右遞增,Y向上遞增、Z向前遞增。

兩者之間的差別只在於 Z軸遞增方向。

Unity3D 在坐標軸的使用上比較特殊,在編輯器和 Script都是使用左手座標系,

但因為渲染底層是使用 OpenGL,所以在 Shader 上是使用右手座標軸。

  • 座標轉換
不管是使用哪個坐標系,渲染的最終目的都是要將 3D 空間轉換到 2D螢幕上。

通常在轉換上會經過三次處理,

分別為: model (world) transform、view transform 和 projection transform。

接下來會分別針對這 3種轉換一一說明。


  • model (world) transform
在使用 3D建模軟體(ex. 3DMax , Blender, etc..)時,會以原點為中心去建造一個模型,

並儲存成檔案輸出給所有遊戲編輯器使用。

這個檔案只包含了模型的基本形狀,並沒有包含在遊戲中出現的位置、角度或大小。

因此在渲染這個模型時,需要將這個模型放到遊戲場景中的指定位置,

並根據需求將其旋轉或縮放。

這個轉換就叫做 model (world) transform。


  • view transform
當模型轉換到遊戲場景中的指定位置之後,接下來需要判定但是否會出現在畫面中。

判定是否出現在畫面是根據模型和攝影機的相對位置。

模型離攝影機太遙遠或是在攝影機看不到的角落(ex. 攝影機背後),都不應該出現在螢幕上。

這種將 3D座標變換成與攝影機的相對座標的轉換就叫做 view transform。



  • projection transform
當決定了相對位置後,就要根據相對位置去做裁切,

標示那些模型需要被顯示,這樣的轉換就叫做 projection transform。



經過上述的3個轉換後,模型位置會落在一個叫做 clipping space 的三維空間內,

並設定在這個空間內的指定範圍才會被顯示到螢幕上。

圖片來源 : OpenGL view volume




  • Clipping Space
Clipping Space 定義了 X、Y軸的範圍再 [-1,1],超出這個範圍就不顯示。

要注意的是,根據 Unity Manual 的說明,

Z軸的範圍會根據目前使用的 Graphic API 而有不同。

當使用 DirectX 時, Z 軸範圍在 1~0 (1是最近,0是最遠)

當使用 OpenGL 時, Z軸範圍在 -1~1(-1最近,1是最遠)。

這個 Z軸遠近和上面提到的左(右)手坐標系描述完全相反。

目前並沒有找到詳細文件說明為何 Clipping Space 的Z軸方向和上述說明不符的原因,

推測可能是上述的轉換全部是在 Shader 內做處理,當 Shader 計算好後會將資料提交給 GPU,

GPU 再轉換到 Normalized Device Coordinate(標準化設備座標,簡稱 NDC) 顯示時,

又做了一次反向 [4]。


  • Unity3D 的座標轉換
在瞭解了基本的做邊轉換之後,來看看 Unity3D 的實際運作。

在前面的說明得知, Unity3D 同時使用了兩種坐標系。

因此 ,需要了解 Unity3D 是如何在這兩個坐標系做轉換,

才能方便我們客製屬於自己的空間轉換。


首先,在 Unity3D 編輯器建立一個空 Scene,

然後把攝影機的 position 和 rotation 都設為 (0,0,0)。

之後隨便放上一個物件(ex. Cube),接著開啟 Frame Debugger 來觀察。

結果發現:


Unity3D 的 View transform 將 Z 軸反轉了 (正值變負值)。

由於左手座標軸和右手座標軸的差別只在於 Z 軸方向,

因此可以得知 Unity3D 是在 View transform 的時候將左手座標系轉成右手座標系處理。


  • 結論
根據上列討論,整理成下列幾個重點

  1. Unity3D 同時使用左手座標系和右手座標系
  2. Unity3D 在 View transform 將左手座標系和右手座標系做轉換
  3. 座標轉換到 clipping space 後,Unity3D 會根據使用的 Graphic API 決定模型是否顯示。
    • Graphic API 使用 DirectX  顯示範圍在 (1,1,1) ~ (-1,-1, 0)
    • Graphic API 使用 OpenGL 顯示範圍在 (1,1,-1) ~ (-1,-1,1)
  4. 不論 Unity3D 的Graphic API 是使用哪種,渲染底層都是使用 OpenGL,因此坐標系都是要轉換成右手座標系處理。
  5. Clipping space 的模型前後判定和目前使用的 Graphic API 坐標系不一樣,需要注意前後方向的正負值。


  • References
1.Unity Manual
2.OpenGL view volume
3.opengl-tutorials
4.LearnOpenGL

沒有留言:

張貼留言