前提:opengl使用右手座標系,向量列向量,所有矩陣變換均是右乘的形式。
V4*1 =M4*4 * V4*1
參加之前的一篇blog:http://blog.csdn.net/dizuo/archive/2008/04/17/2302364.aspx
一、理論
父座標系:
(x,y,z)T是父座標系中任意一點,三個座標基: (1,0,0), (0,1,0), (0,0,1)。
孩子座標系:
原點在父座標系的座標為:P = (Px,Py,Pz)T ,三個座標基為Right,Up,Look,縮寫為:R,U,L, (x',y',z')T點是孩子座標系中的任意一點。
1)公式的數學推導
將孩子座標系的(x',y',z')T點轉化到父座標系中:
筆誤:最後一個等式 44矩陣第一列的前三行應該分別是Rx, Ry, Rz
2)公式的直觀理解:4*4矩陣可以分為3*3的旋轉矩陣RotMat和一個3*1的平移向量TransVec:
[RT, UT, LT], [-RT.dot(P), -UT.dot(P), -LT.dot(P)
]
3*3的矩陣將父座標系的三個座標軸旋轉成R,U,L:
(1,0,0) *RotMat=(Rx, Ry,
Rz)
(0,1,0) *RotMat=(Ux, Uy,
Uz)
(0,0,1)*RotMat=(Lx, Ly, Lz)
根據上面三個等式也可以確定RotMat = [RT, UT, LT],將RotMat擴充為4*4的矩陣:
M44 =
該矩陣可以把父座標系中的P點變換為孩子座標系的原點,即:
(Px, Py, Pz,1) * M44 = (0,0,0,1)
進而解方程得出:
a
= -P.dot(R)
b
= -P.dot(U)
c
= -P.dot(L)
二、代碼實現
opengl中的gluLookAt函數:eye,target,up
//eye 為眼睛位置,target為看的目標位置,up為照相機的正方向<br />Matrix4<Type> MakeView( const gtl::Vec3<Type>& eyes, const gtl::Vec3<Type>& target, const gtl::Vec3<Type>& up)<br />{<br />// f-> look/z<br />// u-> up/y<br />// s-> right/x<br />gtl::Vec3<Type> f = target - eyes;f.normalize();<br />gtl::Vec3<Type> s = f.cross(up);s.normalize();<br />gtl::Vec3<Type> u = s.cross(f);<br />Type sdote = s.dot(eyes);<br />Type fdote = f.dot(eyes);<br />Type udote = u.dot(eyes);<br />return Matrix4<Type>(<br />s.x(),u.x(),-f.x(), 0.0,<br />s.y(),u.y(),-f.y(), 0.0,<br />s.z(),u.z(),-f.z(), 0.0,<br />-sdote, -udote, fdote, 1 );<br />}
對比最終的Matrix4矩陣和第一部分中的推導,會發現第三列差個符號:因為opengl中視點必須位於z軸負方向,視線方向為-z方向,所以最終4*4矩陣中L分量取負,而LT.dot(P) 平移分量為正。
三、應用
1,全局座標系變換到視點座標系:
opengl中gluLookAt函數:
gluLookAt(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz)
計算視點座標系:
Look向量為:(centerx-eysx, centery-eyey,centerz-eyez)T,單位化Look;
Up單位化
Right = Cross( Look, UP )
再從新計算一次:Up = Cross(Right, Look)
gluLookAt函數定義:http://www.opengl.org/sdk/docs/man/xhtml/gluLookAt.xml
2,情境中層次座標系轉化,全局座標系和局部座標系的轉化,一個M44矩陣搞定。