前言:
文章一樣有放在
個人網站。
視覺化視錐體
建構Matrix4x4資料以紀錄相機視錐,使用方向向量逐漸推出視錐體四個頂點方位。
用goUp和goRight向量去推出far plane的上下左右四個頂點。
使用GL函式庫直接渲染一個覆蓋畫面之平面。
_rmMaterial之著色器腳本:
結果:
距離場 (Signed Distance Field ,SDF)
如何用數學公式畫出一個3D的球體? 為甚麼它可以這樣運作? 就得先了解隱函式:
找出所有符合隱函式 f(x,y,z)=0 的點可以畫出一圖形,而隱含式的好的好處在於任一座標帶入隱函式子的結果若<0,則代表在圖形內;等於0表示在圖形(表面)上,>0表示在圖形外。缺點是隱函式不直覺,顯函式比較好懂,例如比起x^2+y^2+z^2,用cos和sin畫圓會更直覺。
*cos和sin無法透過分離變數找到奇異解。
定義圓的公式
回傳距離圓表面的最短距離。
定義SDF
輸入 任意點p到球體原點(暫定為 0,0,0)的距離 與 球體半徑。
假設世界座標為(0,0,-10),則此函數會回傳8。
定義Ray march函數
SDF自發光渲染
我們知道渲染的基本光源有: 自發光(Albedo)、漫射光(Diffuse)、高反射光(Specular )與環境光(Ambient)。但我們的這個"球體"並沒有真正的幾何,該如何補足它的幾何資訊呢?
建立法線
結果:
打光
之後就跟以前算幾何體的方法差不多。
結合場景
修改成讓使用者能從C#那邊設定球體的座標。
有個問題是沒有深度檢測,導致錯誤渲染在最上層。
深度檢測
將深度值投影在該ray的方向向量上,可得到相對的長度,與目前已行走的距離作比較即可。
無限延伸
透過mod的操作讓SDF值不斷在一定範圍內循環。
影子
硬陰影
從目前座標向光(這裡是世界光)的方向發射出Ray,若該Ray行進路上會打到SDF表面,代表該座標處於陰影處。
軟陰影
這邊採用penumbra shadow (半影)作法,使用離表面的距離與目前移動的距離之比例做為陰影強度係數,即不需要採用Blur作法就能有不錯的混合感。
Ray移動三次,對陰影強度係數變化之示意圖。
光追 (Ray Trace)
Ray March是實現光追的一種做法,搭配SDF去做"理論上"的Ray的碰撞檢測。實際不規則形狀之遊戲場景要如何做ray的碰撞檢測才是難題。這邊仍繼續使用SDF做檢測,並搭配上回之
動態環境貼圖作法讓反射更豐富。
以下影片示範從Ray彈跳次數0提升到10的變化過程:
將RayMarch返回值改成布林值:
測試時發現TEXCUBE若sample多餘一次就會出現error,所以只有在ray第一次打到表面時採樣場景顏色,其餘之後皆只是採樣光亮程度,不斷的複寫在本身的像素上,因此看起來像是素模。