
上個月學習Peter Shirley-Ray Tracing in One Weekend的系列三本書,收獲真的很多。這個系列的書真的是手把手教你如何從零開始建構一個光線跟蹤渲染器,對新手(像我)非常友好。但是書中有很多章節需要有一定的數學功底才能看懂,本文想分享一下關于in One Weekend-chapter 8:Metal中一筆帶過的折射公式推導,内容主要來自于《Mathematics for 3D Game Programming and Computer Graphics, 3rd Edition》[1],加上我個人的了解,如有錯誤,歡迎指出。
(配圖為raytracer建構後渲染)
問題簡述
已知入射向量 \(L\) 和交點法線 \(N\),和入射光線所在媒體折射率 \(\eta _ { \mathrm { L } }\) 及折射光線所在媒體折射率 \(\eta _ { \mathbf { T } }\) ,求折射向量 \(T\)。如圖:
- 設入射角為 \(\theta _ { \mathrm { L } }\) ,折射角為 \(\theta _ { \mathbf { T } }\)
- 設 \(L\) 和 \(N\) 已經标準化為機關向量,所求 \(T\) 也為機關向量
- 注意此處 \(L\) 的方向指向外,保留與書上一緻(實際入射方向應為\(-L\))
- L、T可以了解為light和transmission的縮寫
圖 1
推導過程
(若推導過程感覺了解困難可以先考慮二維情況再考慮三維,其實入射光線和折射光線都在一個二維平面上)
關鍵公式:折射定律或斯涅爾定律(Snell's Law),用于計算折射角 \(\theta _ { \mathbf { T } }\) :
推導思路:
将 \(T\) 分解為平行于 \(N\)(-\(N\)) 和垂直于 \(N\) 的向量 (\(-G\)),見圖 1。(用這兩個向量的線性組合\(a*-N+b*G\)表示 \(T\),問題就在于求兩個系數a、b和向量 \(G\),将問題轉換為求\(a\)、\(b\)、\(G\))
1. 求 \(a\)
求\(a\)實際上就是求向量\(T\)在向量\(-N\)上的投影,利用點乘公式即可計算出\(a=\cos \theta _ { \mathrm { T } }\),由于所求 \(T\) 和 \(-N\) 都為機關向量,是以其點乘展開式最終化簡為\(\cos \theta _ { \mathrm { T } }\)。
\(T \cdot (-N) = |T| |-N| \cos \theta _ { \mathrm { T } }=\cos \theta _ { \mathrm { T } }\)
\(T \cdot (-N) = |-N|\cdotp Proj = Proj\)
聯立上式即可
2. 求 \(b\)
基本思路和求 \(a\) 一樣,這裡求出 \(b = \sin \theta _ { \mathrm { T } }\)
(實際此處先求出的是cos<T,-G>,根據由于垂直關系,兩角互餘,等值于 \(\sin \theta _ { \mathrm { T } }\) )
3. 求 \(G\)
\(G\) 同 \(\operatorname { perp } _ { \mathrm { N } } \mathbf { L }\)平行(\(\operatorname { perp } _ { \mathrm { N } } \mathbf { L }\)為\(L\)垂直于\(N\)的分量,見圖 1),由于 \(L\) 為機關向量,\(\left\| \operatorname { perp } _ { \mathbf { N } } \mathbf { L } \right\| = \sin \theta _ { \mathbf { L } }\),\(G\) 可表示為:
(求 \(\operatorname { perp } _ { \mathrm { N } } \mathbf { L }\) 的過程有點像施密特正交化的過程,都是一個向量去除某個方向的分量,除以 \(\sin \theta _ { \mathbf { L } }\) 即标準化為機關向量)
4. 是以 \(T\) 可以表示為:
利用斯涅爾定律替換\(\frac { \sin \theta _ { \mathrm { T } } } { \sin \theta _ { \mathrm { L } } }\):
将 \(\cos \theta _ { \mathrm { T } }\) 用 \(\sqrt { 1 - \sin ^ { 2 } \theta _ { \mathrm { T } } }\)代替,\(\sin \theta _ { \mathrm { T } }\) 用 \(\left( \eta _ { \mathrm { L } } / \eta _ { \mathrm { T } } \right) \sin \theta _ { \mathrm { L } }\) 代替:
最後,将 \(\sin ^ { 2 } \theta _ { \mathrm { L } }\) 用 \(1 - \cos ^ { 2 } \theta _ { \mathrm { L } } = 1 - ( \mathbf { N } \cdot \mathbf { L } ) ^ { 2 }\) 帶入可得最終 \(T\) 的表達式:
(如果 \(\eta _ { \mathbf { L } } > \eta _ { \mathbf { T } }\),方程式中根号内的量可能為負,光線發生全反射,應用反射公式計算向量方向。即當 \(\sin \theta _ { \mathrm { L } } \leq \eta _ { \mathrm { T } } / \eta _ { \mathrm { L } }\),上式才可用于計算折射向量。)
其他
最後放一張in one weekend中計算折射向量的函數,參數 v 即為入射光線方向,隻要将上訴公式加以對照即可寫出。(記得上述 \(-L=v\))
折射向量計算(Refraction Vector Calculation)
參考文獻
- Eric Lengyel. Mathematics for 3D Game Programming and Computer Graphics, 3rd Edition. Course Technology PTR, 2011.
- Peter Shirley. Ray Tracing in One Weekend. Amazon Digital Services LLC, January 26, 2016.