下面應用《微分幾何》中的歐氏空間等距變換,導出從世界座標系到觀察座標系的變換,並結合directx9.0和C++來實現一個簡單的相機類。
1。假設世界座標系用I=(i,j,k)和O(0,0,0)來表示,觀察座標系用E=(e1,e2,e3)和P(a,b,c)來表示,其中,E=A*I(這裏E和I表示爲列向量)。A爲正交矩陣,由A1=(a11,a12,a13),A2=(a21,a22,a23),A3=(a31,a32,a33)組成。
2。設世界座標系中的任意一點Q(x,y,z)在觀察座標系中表示爲(x0,y0,z0),於是有OQ = OP + PQ (向量,由於不太方便,在此並未給出圖形)
(x,y,z)*I = (a,b,c)*I + (x0,y0,z0)*E, (I,E爲列向量)
(x,y,z)*I = (a,b,c)*I + (x0,y0,z0)*A*I; (E=A*I)
於是有(x0,y0,z0)* A= (x,y,z) - (a,b,c);
(x0,y0,z0) = ((x,y,z) - (a,b,c))*A-1; (A-1表示A的逆)
(x0,y0,z0) = ((x,y,z) - (a,b,c))*At; (At表示A的的轉置,因爲A爲正交矩陣,逆等於轉置)
用齊次座標表示爲
(x0,y0,z0) = (x,y,z)*B; (B爲A的逆矩陣)
B由 B1=(a11,a21,a31,0),B2 =(a12,a22,a32,0),B3 = (a13,a23,a33,0),B4 =(-a*e1,-b*e2,-c*e3,1)組成
因此相機類的代碼如下,僅給出部分代碼
class CCamera
{
public:
CCamera(); //構造函數
virtual ~CCamera(){}; //析構函數
void GetMatrix(D3DXMATRIX& matrix) ; //獲得變換矩陣
void SetPosition(const D3DXVECTOR3& pos); //設置位置
void GetPosition(D3DXVECTOR3& pos) const; //獲得位置座標
virtual void Walk(float units) = 0; //前後移動
virtual void Strafe(float units) = 0; //左右移動
virtual void Fly(float units) = 0; //上下移動
virtual void Pitch(float angle); //仰俯
virtual void Yaw(float angle); //偏航
virtual void Roll(float angle)=0; //滾動
protected:
D3DXVECTOR3 m_position; //位置(P)
D3DXVECTOR3 m_right; //右向量(e1)
D3DXVECTOR3 m_up; //上向量(e2)
D3DXVECTOR3 m_look; //方向向量(e3)
};
//計算觀察矩陣
void CCamera::GetMatrix(D3DXMATRIX& matrix)
{
//規範化向量
D3DXVec3Normalize(&m_look,&m_look);
D3DXVec3Cross(&m_up,&m_look,&m_right);
D3DXVec3Normalize(&m_up,&m_up);
D3DXVec3Cross(&m_right,&m_up,&m_look);
D3DXVec3Normalize(&m_right,&m_right);
//計算A的逆矩陣B
matrix._11 = m_right.x; matrix._12 = m_up.x; matrix._13 = m_look.x; matrix._14 = 0; //B1
matrix._21 = m_right.y; matrix._22 = m_up.y; matrix._23 = m_look.y; matrix._24 = 0; //B2
matrix._31 = m_right.z; matrix._32 = m_up.z; matrix._33 = m_look.z; matrix._34 = 0; //B3
//B4
matrix._41 = - D3DXVec3Dot(&m_position,&m_right);
matrix._42 = - D3DXVec3Dot(&m_position,&m_up);
matrix._43 = - D3DXVec3Dot(&m_position,&m_look);
matrix._44= 1.0f;
}