折射向量計算(Refraction Vector Calculation)


上個月學習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\))

參考文獻

  1. Eric Lengyel. Mathematics for 3D Game Programming and Computer Graphics, 3rd Edition. Course Technology PTR, 2011.
  2. Peter Shirley. Ray Tracing in One Weekend. Amazon Digital Services LLC, January 26, 2016.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM