The Matrix
丁欧南
Keyword:[3D Math][Matrix][矩阵操作]
在这篇文章里我将介绍三个矩阵,分别对应于OpenGL中的glTranslate,glRotate,glScale.虽然OpenGL中的这三个函式操作起来很方便,但我认为学习矩阵的内部原理,一方面有利于更好地理解3D程式的思维方式,正所谓under the hood;另一方面使你能够得心应手地驾驭3D程式写作的一些高级技巧(如Cg).
这篇学习笔记出自我这样一个初学者之手,我希望通过此文与诸位共进步.
A.
基础(IMO)
矩阵(Matrix)本质上就是这样一种东西:方便的坐标系统转换器.
为什么把它称之为坐标系统转换器呢?我举一个实际的例子:
任务: 给出n个顶点,现要求以某直线axis为轴将这些顶点旋转π/6
解法1:为每个顶点重新计算它的新位置,并修改原先的代码.
即 glVertex3f(0,1,0); 改为 glVertex3f(0.5,sqrt(3)/2,0);
解法2:在旧顶点与新顶点之间建立映射关系.vertex’=f(vertex)
源代码无需修改,只要在实际渲染前把旧顶点坐标映射到新顶点坐标即可.
解法2就是矩阵的思维.解法2与解法1在效果上完全相同.也就是说: 矩阵为你所提供的
服务就是:坐标转换自动化,除此之外同手工效果一样.
B.
约定
使用纯系坐标系统(Homogeneous Coordinate)
平移部分位于最后一行(row)
这样做的目的是使你能把所见之矩阵无需修改,直接写入你的OpenGL代码
[a11 a12 a13 a14]
[a21 a22 a23 a24]
[a31 a32 a33 a34]
[a41 a42 a43 a44]
GLfloat matrix[]={a11,a12,a13,a14,a21,a22,a23,a24,a31,a32,a33,a34,a41,a42,a43,a44};
叉积(Cross Product): × 点积(Dot Product): *
C.
右手定则
1.OpenGL右手坐标系统
伸出右手,伸出拇指,食指,中指,且中指与食指垂直.这时中指,拇指,食指分别对应OpenGL坐标的x,y,z的正方向.
2.叉积右手定则
伸出右手,四指并拢,拇指竖直向上
P×Q
如果右手手指沿P,手掌面对着Q,那么拇指就指出了P×Q的方向
3.旋转右手定则
伸出右手,四指握住要旋转的轴,拇指朝向轴的正方向,向身体内侧转动手腕,这时旋转的角定为正角
D.
平移(Translate)
只要将原顶点加上要平移的距离即可.
[1 0 0 0]
[0 1 0 0]
[0 0 1 0]
[sx sy sz 1]
E.
旋转(Rotate)
E1 绕X轴旋转
[1 0 0 0]
[0 cosθ sinθ 0]
[0 -sinθ cosθ 0]
[0 0 0 1]
E2 绕Y轴旋转
[cosθ 0 -sinθ 0]
[0 1 0 0]
[sinθ 0 cosθ 0]
[0 0 0 1]
E3 绕Z轴旋转
[cosθ sinθ 0 0]
[-sinθ cosθ 0 0]
[0 0 1 0]
[0 0 0 1]
E3 绕任意轴旋转
我假定此轴一定过原点,否则我可以用D中提到的平移矩阵将此轴移到原点.
V
up⊥V
perp |V
up|=|V
perp|=|V
aux| V
proj⊥V
perp n∥V
proj n为单位向量
绕n旋转V θ度到V’, 求V’
V
proj=|V
proj|/|n| n
n*V=|n||V|cosβ cosβ=|Vproj|/|V| |Vproj|=|V|cosβ
n*V=|n||V
proj| |V
proj|=(n*V)/|n|
Vproj=(n*V)/|n|2 n 因为 n 为单位向量
所以 Vproj=n*V n
Vperp=V-Vproj=V-n*V n
V
up=V
perp×n=(V-n*V n)×n=V×n-n*V(n×n)=V×n
V
aux=-sin(θ-90)V
perp+cos(θ-90)V
up=sin(90-θ)V
perp+cos(90-θ)V
up
=cosθV
perp+sinθV
up=cosθ(V-n*V n)+sinθ(V×n)
V’=Vperp+Vaux=n*v n+cosθ(V-n*V n)+sinθ(V×n)
F
缩放(Scale)
已知 被缩放向量 V 缩放方向 n (Normaled) V,n交角θ Vperp ⊥ Vproj 缩放倍数 s 求V’
Vproj=|Vproj|/|n| n cosθ=|Vproj|/|V|
所以 cosθ|V| =|Vproj|
n*V=cosθ|V| |n| = |Vproj| |n| |Vproj| = n*V/|n|
代入第一个式子: Vproj = n*V/|n|2 n 又n已是单位向量
所以 Vproj = n*V n Vtarget = s Vproj =s n*V n
Vperp = V-Vproj = V-n*V n
V’=Vtarget+Vperp = s n*V n+V-n*V n = V+(V*n)(s-1)n