【翻譯】法線矩陣

在渲染中,有很多的計(jì)算是在視角空間中完成的。這是因?yàn)楣庹胀ǔJ窃谶@個(gè)空間中計(jì)算的,否則,像一些依賴視角的效果,比如高光,將會(huì)比較難以實(shí)現(xiàn)。

因此,我們需要一種方法將法線轉(zhuǎn)換到視角空間。我們可以通過下面的寫法把一個(gè)頂點(diǎn)轉(zhuǎn)換到視角空間:

vertexEyeSpace = gl_ModelViewMatrix * gl_Vertex;

那么,我們?yōu)槭裁床荒苤苯影堰@個(gè)應(yīng)用到法線向量呢?首先,法線是一個(gè)3維向量,而ModelView矩陣是一個(gè)4x4矩陣;其次,因?yàn)榉ň€是一個(gè)向量,所以我們只需要轉(zhuǎn)換它的方向。ModelView矩陣左上方的3x3子矩陣包含了方向的信息,那么我們?yōu)槭裁床荒苁褂眠@個(gè)子矩陣去轉(zhuǎn)換法線呢?

這可以通過下面的代碼很簡(jiǎn)單的實(shí)現(xiàn):

normalEyeSpace = vec3(gl_ModelViewMatrix * vec4(gl_Normal,0.0));

但上面的代碼只在部分情況下可以正常工作。

讓我們來看下一個(gè)潛在的問題:

在上面的圖中,我們看到一個(gè)帶了一個(gè)法線和切線向量的三角形。在下面的圖中,顯示了如果ModelView矩陣包含了非均勻縮放會(huì)發(fā)生什么樣的偏差。

注意:如果是均勻縮放,那么法線的方向?qū)?huì)保持,雖然長(zhǎng)度會(huì)受到影響,但可以簡(jiǎn)單的通過標(biāo)準(zhǔn)化修復(fù)。

在上面的圖中,ModelView矩陣應(yīng)用到了所有的向量,包括法線,結(jié)果是顯而易見的錯(cuò)誤的:轉(zhuǎn)換后的法線不再與表面垂直了。

我們知道,一個(gè)向量可以表示為兩個(gè)點(diǎn)之間的差異。比如切線向量,它可以通過計(jì)算三角形一條邊上的兩個(gè)頂點(diǎn)之間的差距來獲得。如果P1P2是定義一條邊的兩個(gè)頂點(diǎn),那么我們知道:

T = P2 - P1

如果把這個(gè)向量表示為包含4個(gè)元素且最后一個(gè)元素為0的元組,那么我們可以把這個(gè)等式兩邊都乘以ModelView矩陣

T * ModelView = (P2 - P1) * ModelView

結(jié)果是

T * ModelView = P2 * ModelView - P1 * ModelView
T' = P'2 - P'1

因?yàn)?strong>P'1P'2為轉(zhuǎn)換后的三角形的頂點(diǎn),所以T'仍然與三角形的邊相切。因此,ModelView保持了切線。但它卻沒有保持法線。

使用和T向量一樣的方法,我們可以找到兩個(gè)點(diǎn)Q1Q2,讓以下等式成立

N = Q2 - Q1

主要的問題是,就如上面的圖所展示的那樣,由轉(zhuǎn)換后的的點(diǎn)定義的向量,Q2 - Q1,不一定仍然與邊垂直。法線向量不是如切線向量那樣,定義為兩個(gè)點(diǎn)之間的差距,它定義為垂直于一個(gè)表面的向量。

現(xiàn)在我們知道了,我們不能在所有情況下使用ModelView來轉(zhuǎn)換法線向量。那么我們應(yīng)該使用什么樣的矩陣呢?

假設(shè)G為一個(gè)3X3的矩陣,讓我們看看如何計(jì)算它來正確的轉(zhuǎn)換法線向量。

我們知道,在矩陣轉(zhuǎn)換之前,因?yàn)榍芯€和法線向量是垂直的,所以T.N = 0。我們也知道,轉(zhuǎn)換之后,它們也一定要垂直,所以N'.T'也一定要等于0。我們把ModelView的左上方的3x3矩陣稱為M矩陣,T可以安全的乘以MT是一個(gè)向量,所以w元素是0).

我們假設(shè)G是正確轉(zhuǎn)換法線向量N的矩陣,那么就有了下面的等式

N'.T' = (GN).(MT) = 0

把點(diǎn)乘轉(zhuǎn)換為叉乘,那么

(GN).(MT) = (GN)T * (MT)

注意為了叉乘向量,第一個(gè)向量的轉(zhuǎn)置是必須的。我們知道兩個(gè)矩陣相乘的轉(zhuǎn)置,等于轉(zhuǎn)置后矩陣的相乘,但順序要相反,因此:

(GN)T * (MT) = NTGTMT

我們前面已經(jīng)說過了NT的點(diǎn)乘是0,所以如果

GTM = I

那么我們有

N'.T' = N.T = 0

這正是我們要的,所以我們可以根據(jù)M來計(jì)算G。

GTM = I <==> G = (M-1)T

因此M矩陣的逆矩陣的轉(zhuǎn)置,是正確轉(zhuǎn)換法線的矩陣。

前面我們說直接使用ModelView矩陣在部分情況下可以正常工作。當(dāng)ModelView左上方的3x3矩陣是正交矩陣的時(shí)候,我們有:

M-1 = MT ==> G == M

這是因?yàn)檎痪仃嚨霓D(zhuǎn)置與逆矩陣是一樣的。那么什么是正交矩陣呢?正交矩陣就是矩陣的每行/列都是單位長(zhǎng)度,并且互相垂直的矩陣。這意味這兩個(gè)向量,被正交矩陣轉(zhuǎn)換前后,它們之間的角度是一樣的,因此轉(zhuǎn)換后的法線依然垂直于切線。此外,它還保持了向量的長(zhǎng)度。

那么我們?nèi)绾伪WCM是正交的呢?只要我們限制我們的幾何變換僅限于旋轉(zhuǎn)和位移,比如在OpenGL程序中我們僅僅使用glRotateglTranslate,不使用glScale,那么可以確保M是正交的。注意:gluLookAt也創(chuàng)建了一個(gè)正交矩陣。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容