GLSL学习 -- gl_NormalMatrix

Posted on 2009-06-24 10:30 夏冰 阅读(998) 评论(2)  编辑 收藏 引用 所属分类: OpenGL
参考资料:http://www.lighthouse3d.com/opengl/glsl/index.php?normalmatrix

由于需要在视觉空间进行大量的计算, 所以光照需要在视觉空间中进行计算.
因此我们需要求出视觉空间中的法线向量.
转换一个顶点进入视觉坐标的公式如下:
vertexEyeSpace = gl_ModelViewMatrix * gl_Vertex;
但是为何我们不能够对法线向量做相同的事情呢?
首先, 法线向量是一个拥有三个元素的一维向量, 模型视图矩阵则是4x4矩阵
这点可以用下面的代码轻易解决:
normalEyeSpace = vec3(gl_ModelViewMatrix * vec4(gl_Normal, 0.0));
所以,gl_NormalMatrix仅仅是上面的剪切代码么? 不, 这不是真的. 上面的代码可以用于一些环境, 但不能作用于所有.
让我们看看下面潜在的问题:

在上图我们看到一个三角形, 有一个法线向量和切线向量. 接下来的图显示当一个观察矩阵缩放的时候所显示的情景.(如调用glScale)
如果我们还是调用上面的代码的话.

注意: 当观察矩阵各方向尺寸不一致时,应当预先保存法线的方向, 虽然法线的长度会变化,但是单元化很易修复
在上图, 观察矩阵影响到所有的顶点以及法线. 很明显这个结果是错误的. 法线并不垂直于切线.

所以现在我们得知并不能将观察矩阵应用于所有的法线. 所以我们应当应用怎样的矩阵呢?

注意到T*N = 0. 所以在视觉空间中, 两者还应当是垂直的, 保证转换后的T'*N' = 0.
假设矩阵G是转换法线N的矩阵.T则乘观察矩阵左上的3*3矩阵M(T是一个向量, 令w为0).式子如下:


点积可以转换成向量积, 如下


由于N"T = 0, 所以我们猜想
(I为单位矩阵)
所以


因此gl_NormalMatrix等于M的逆矩阵的倒置矩阵

在本文的开始曾说模型观察矩阵作用于法线向量有时候也有效, 这是因为观察矩阵为正交矩阵, 即

正交矩阵 ---- 任意列/行向量都为单元长度向量. 并相互垂直.
这意味着任意两个向量乘以该向量, 向量间的角度不会发生任何变化.

如果我们仅仅在观察矩阵进行旋转或者移动,我们的当前模型矩阵仍为正交矩阵.
即我们只用glRotate和glTranslate命令,而不用glScale命令.
注意: 我们glLookAt产生的观察模型矩阵也是正交矩阵.

Feedback

# re: GLSL学习 -- gl_NormalMatrix[未登录]  回复  更多评论   

2009-12-30 14:04 by tiny
齐次,点变换与线变换不同,点就是modelviewproj,线就是modelviewproj的逆转置

# re: GLSL学习 -- gl_NormalMatrix  回复  更多评论   

2010-09-01 16:18 by MoMo
1、平移矩阵是有效的,不是因为平移矩阵的正交性[平移矩阵不是正交阵]。是因为两个原因:

1)、平移矩阵对法向量无效,因为它是向量,不是点

设有两个点的齐次坐标为:v1'(x1, y1, z1, 1); v2'(x2, y2, z2, 1)

然后这两点的直线的法向量为:n'(nx, ny, nz, 0);注意最后一个0

移动a、b、c的平移矩阵为:T(a, b, c) =

1 0 0 a

0 1 0 b

0 0 1 c

0 0 0 1

可以验证:

T * v1' = (x1+a, y1+b, z1+c, 1)
T * v2' = (x2+a, y2+b, z2+c, 1)
但是:T * n' = (nx, ny, nz, 0),所以得到平移变换对向量无效(这也符合常识)

2)、v1', v2'变换后的点如上所示,则:它们代表直线的向量还是和原来一样,v12' =(x2 - x1, y2 - y1, z2 - z1, 0),然后:v12' * n'还是等于0;

2、同样道理,缩放矩阵也不是正交矩阵,但是缩放分两种,一种是均匀缩放,一种是非均匀缩放,对于均匀缩放,也是可以用点变换矩阵来做的,原理如下:

均匀缩放矩阵S,三个轴的缩放系数皆为a, S(a) =

a 0 0 0

0 a 0 0

0 0 a 0

0 0 0 1

所以:

S * v1' = (x1*a, y1*a, z1*a ,1)

S * v2' = (x2*a, y2*a, z2*a ,1)

S * n' = (nx*a, ny*a, nz*a ,0)

所以变换后的线向量为:v12 = (a*(x1-x2), a*(y1-y2), a*(z1-z2), 0)
所以变换后的法向和v12点乘时候可以把共用系数a抽出来,就变成了a^2乘以原来的乘积,还是0

至于非均匀缩放,是不能有这种结果的,所以不能用这种办法了。

3、至于文中的最后一句:“注意: 我们glLookAt产生的观察模型矩阵也是正交矩阵“,其实不是,原因是因为:相机操作除了旋转到正确的轴之外,还有平移到世界原点,回到1,平移矩阵不是正交阵,所以结果不一定是正交的,不过如果相机位置就设在原点,那就肯定是正交的。

呵呵。

博问 - 解决您的IT难题

博客园  博问  IT新闻  C++程序员招聘
标题  
姓名  
主页
验证码 *
内容(提交失败后,可以通过“恢复上次提交”恢复刚刚提交的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
[使用Ctrl+Enter键可以直接提交]
网站导航: 博客园   IT新闻   BlogJava   知识库   程序员招聘   管理


posts - 60, comments - 44, trackbacks - 0, articles - 0

Copyright © 夏冰