Opengl的gl_NormalMatrix【转】

时间:2023-01-31 16:25:08

原文地址:http://blog.csdn.net/ichild1964/article/details/9728357

参考:http://www.gamedev.net/topic/598985-gl-normalmatrix-in-glsl-how-to-calculate/

当用glsl传normal到fragment的时候总要用gl_Normal* gl_NormalMatrix,是为什么呢?做bumpmap的时候,binormal和tangent需不需要也乘以gl_NormalMatrix呢,如果需要把TBN转到世界空间,而不是把灯光转到TBN的话需不需要乘以gl_NormalMatrix或者是需要乘以其它矩阵?有没有想过perspective投影之后模型成什么样子呢?在Direct3D你不需要关心这些,因为都处理好了,所以一路稀里糊涂下来效果也基本上做的出来,在OpenGL就不行了。下面解释了什么是 gl_NormalMatrix,简而言之gl_NormalMatrix是为了令法线在perspective projection之后和投影后的模型平面依然垂直,但是它并不是投影矩阵哦,而是投影矩阵的逆矩阵的翻转矩阵Opengl的gl_NormalMatrix【转】 。呵呵,顺便想象下投影后的物体是什么样子吧,这样就会幡然醒悟为什么需要重新找垂直于平面的发现了。

Normal Matrix

Normals are funny.  They're vec3's, since you don't want perspective on normals.   And they don't actually scale quite right--a 45 degree surface with a 45 degree normal, scaled by glScalef(1,0.1,1), drops the surface down to near 0 degrees, but actually tilts the normal *up*, in the opposite direction from the surface, to near 90 degrees.

Mathematically,
if between two points a and b on the surface, dot(n,b-a)==0, then after
applying a matrix M to the points, you want the normal to still be
perpendicular.  The question is, what matrix N do you have to apply to
the normal to make this happen?  In other words, find N such that
    dot( N * n , M * a - M * b) == 0

We
can solve this by noting that dot product can be expresed as matrix
multiplication--dot(x,y) = transpose(x) * y, where we treat an ordinary
column-vector as a little matrix, and flip it horizontally.  So
   transpose(N * n) * (M*a - M*b) == 0         (as above, but write using transpose and matrix multiplication)
   transpose(N * n) * M * (a-b) == 0              (collect both copies of M)
   transpose(n) * transpose(N) * M * (a-b) == 0    (transpose-of-product is product-of-transposes in opposite order)

OK. 
This is really similar to our assumption that the original normal was
perpendicular to the surface--that dot(n,b-a) == transpose(n) * (a-b) ==
0.  In fact, the only difference is the new matrices wedged in the
middle.  If we pick N to make the term in the middle the identity, then
our new normal will be perpendicular to the surface too:
    transpose(N) * M == I   (the identity matrix)
This is the definition for matrix inverses, so the "normal matrix" N = transpose(inverse(M)).

If
you look up the GLSL definition for "gl_NormalMatrix", it's defined as
"the transpose of the inverse of the gl_ModelViewMatrix".  Now you know
why!