下面应用《微分几何》中的欧氏空间等距变换,导出从世界坐标系到观察坐标系的变换,并结合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;
}