2013-07-01 76 views
3

當我們要在頂點着色器中計算光時,我們需要視圖空間中的法向量。一般來說,它看起來如下(從OpenGL Superbible 5th開始):將頂點變換爲頂點着色器中的視圖空間

// normalMatrix is retrieved from GLMatrixStack modelViewMatrix 
vec3 vEyeNormal = normalMatrix * vNormal 

我想在不使用GLT庫的情況下編寫程序。在另一個源(http://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Diffuse_Reflection)我發現下面的公式:

vec3 normalDirection = normalize(m_3x3_inv_transp * v_normal); 

可變m_3x3_inv_transp計算如下:

glm::mat3 m_3x3_inv_transp = glm::transpose(glm::inverse(glm::mat3(mesh.object2world))); 

我意識到:

我的問題是,爲什麼反演和transponsing矩陣後,我得到NormalMatrix以及如何檢查它與逆向計算?基於對3D遊戲編程和計算機圖形(由埃裏克·倫蓋爾)數學第66頁

回答

3

你的假設並不完全正確。

OpenGL操作順序是Scalng,翻譯,旋轉。

不,一般來說,你可以有一個任意的世界矩陣。這可以包括任何數量的操作。

逆矩陣是撤消上次變換。

否。如果反轉矩陣,則會恢復其整個效果。例如。如果您有一個矩陣圍繞x軸旋轉45°並且由(1,2,3)進行平移,則其反轉將導致(-1,-2,-3)平移,接下來是 - 圍繞x軸45°。

正常矩陣只是模型視圖矩陣的旋轉分量。

不是。如果是這種情況,那麼您可以放棄矩陣的翻譯(以及任何視角)部分。但事實並非如此。

正常矩陣用於轉換法線,以便它們仍然與相應的曲面正交。對於剛體轉換(即旋轉和平移),您可以直接使用世界變換。其中一個原因是你可以通過轉置旋轉矩陣來反轉(因爲它是正交的)。然後你有transpose(transpose(world))這是原始矩陣。

對於一般矩陣,您必須按照您所述計算矩陣。想象一下按(1,2)進行縮放。如果你轉換一個圓圈,它將變成一個橢圓。我們來看看45°的正常值。在這個位置的圓的正常值是(1,1)(未標準化)。如果我們用標度矩陣轉換這個法線,我們可以得到(1,2)。如果你想象轉換後的橢圓,你會發現法線不再與表面正交。所以你必須使用一個不同的變換(在這種情況下,按(1,0.5)進行縮放),這保留了正交性。

+0

感謝您在我的思考和簡單實用的答案中發現錯誤。 – CppMonster

3

答:

切線T和正常N在表面上的特定點必須是垂直的,所以:

N . T = 0 

假設我們使用矩陣M轉換表面。在轉化上的點的切線是:

T' = MT 

我們希望找到一個矩陣G這樣N' = GN是在轉化表面上的點的法線。由於正常的和切線在轉化上的點仍然必須是垂直的,我們有:

0 = N' . T' = (GN) . (MT) = trans(GN) * MT = trans(N) * trans(G) * MT 

現在:

trans(N) * T = N . T = 0 

所以上面會滿意,如果:

trans(G) * M = I 

哪裏:

G = trans(inv(M)) 

換句話說,轉換法線所需的矩陣是用於轉換切線的矩陣的逆矩陣的轉置。

+0

如果我很好理解切線向量(T)總是垂直於曲面將其推廣到不同形狀的曲面,並且矩陣M用於變換此曲面的向量T,N和頂點? – CppMonster

+0

@CppMonster:不,法向矢量總是垂直於表面(按照定義)。假設曲面是多邊形網格,那麼M可以用來變換頂點和切向量,但不是法向量。爲了轉換法向量,需要使用M的倒數的轉置,這就是上面所說的。 –

+1

我在急速寫錯了(顯然N是垂直於表面,它是這個線程的基礎)。我想寫出矢量T垂直於矢量N來泛化不同形狀的表面(如果我對切線有很好的理解)。感謝您提供給我的一些信息,因爲它非常有用且有價值。 – CppMonster