Intro
閱讀之前最好對光線追蹤, 光照方程, 輻照度量學等有一定的瞭解, 且本文只對光子映射做粗淺的介紹.
光子映射 Photon Mapping 和光線追蹤一樣是真實感渲染領域的一種渲染方法. 他能夠很好的解決光線追蹤類方法相對難以處理的 Caustics 等現象. 並且一般情況下能以一定的內存空間爲代價, 獲得更高的效率.
另外與使用 Monte Carlo 的各種光線追蹤方法相比, 當算法出現 Artifact(瑕疵) 的時候, 光線追蹤方法一般呈現高頻信號, 很容易被人眼察覺. 光子映射產生的 Artifact 則多爲低頻信號, 相對不容易被人眼發現.(在圖像上的高頻信號意味着小範圍內顏色上劇烈的變化)
算法核心
光子映射是一個 Two-pass 的方法, 第一個 pass 爲光子追蹤, 第二個 pass 進行渲染
- 光子追蹤(Photon Tracing Pass): 從光源像場景發射攜帶能量的光子, 光子在場景中與物體表面進行交互(反射或折射), 並在非光澤表面物體相交時記錄, 最後將這些光子存儲在一個全局的光子圖(Photon Map)中.
- 渲染(Rendering Pass): 使用傳統的路徑追蹤技術從攝像機通過屏幕向場景中發射光線並在場景中傳輸, 當光線與物體表面相交時, 該頂點光照計算中的漫反射部分則使用統計的方法從前面產生的光子圖中計算得出.
光子追蹤pass與光線追蹤的區別
與光線追蹤不同的是光子映射的光子在與物體表面交互時, 要麼被反射, 要麼被折射, 要麼吸收. 這是根據物體表面的材質參數按概率的方式(如俄羅斯輪盤, Russian Roulette)確定的. 而光線追蹤方法在必要時, 一束光線可以根據表面材質, 一部分被反射, 一部分被折射, 從而分成多束光線.
光子存儲
我們在光子中會存儲: 光子的位置, Flux(功率), 入射方向和一個在 KD-Tree 中使用標誌位.
struct Photon {
float x, y, z; // 位置
char p[4]; // RGBE編碼的flux
char phi, theta; // 入射方向
short flag;
};
使用 FLux 的原因與我們需要使用統計學中的密度估計有關(密度估計也是在照片級真實感渲染領域的渲染方程中經常出現概率密度函數PDF的原因). 密度估計所涉及的數據一定是具有任意可加性的, 那麼像 radiance 這種與方向有關的物理量則不適合使用. Flux 是單位時間內發出的能量, 與方向面積等都無關, 適合存儲在光子中.
光子最終會被存儲到 PhotonMap 中, 我們一般將 PhotonMap 處理爲一顆平衡 KD-Tree. 因爲算法後半在計算某點的 radiance 時會涉及很多空間查找操作, 用 KD-Tree 來存儲光子可以加速光子查找.
Radiance 計算
根據 BRDF 理論, 某點 x 處沿着 w 方向的 radiance 是沿着角度 w’ 方向到達 x 點的 radiance 與 BRDF 係數 f 的乘積在該點半球空間上的積分(公式中的點乘項與立體角, Lambert’s Cosine Law等有關).
爲了計算這個積分, 我們需要知道 p 點處入射的 radiance ( 公式中的 Li ). 光子圖會爲我們提供當前位置附近一定數量光子的 flux, 根據 Radiometry (輻照度量學) 可以進行 radiance 和 flux 之間的轉換.
積分本質上可以理解爲求和, 具體的公式推導我們不做分析, 我們只需要理解: 光子映射通常使用 kNN 最近鄰估計, 通過選擇 p 點一定範圍內的 n 個光子來計算目標位置的 radiance.
參考文獻
Jiff:Lightmass分析之 經典Photon Mapping算法介紹
Jiff:LightMass源碼分析之光子追蹤實現
Jiff:LightMass源碼分析之光照評估
《Physically Based Rendering : From Theory to Implementation》Matt Pharr
《全局光照技術 從離線到實時渲染》秦春林
《A Practical Guide to Global Illumination using Photon Maps》Henrik Wann Jensen