struts Object
{
   D3DMATRIX matLocal;
}
用该矩阵中的三个向量分别表示物体的朝向:Look,Up,Right,这个里的含义如同openGL里边相机的Look,Up,Right是一样的。然而实际上定位一个物体除了上述三个向量表示的姿态以外,还需要一个位置信息,于是我们用第四行来记录位置。将该矩阵设置为单位阵表示物体的变换从原点开始,沿坐标轴方向。这样表示以后,物体绕Look轴转就是横滚(pitch),绕Up轴转就是偏航(yaw),绕Right轴转就是俯仰(roll)。
------------------------------------
   下面说一下用到的API。将一个向量按照指定矩阵变换的API是:D3DXVectorTransformCoord(D3DXVector* vNew,D3DXVector* vOld,D3DXMatrix* mat),那么旋转用的矩阵mat又来源于D3DMatrixRotationAxis(D3DXMatrix* mat,D3DXVector* vAxis,FLOAT fRad),表示绕某一向量旋转一个角度产生一个变换矩阵。有了这两个API我们就可以通过将三个姿态向量指定给vAxis和vOld来获取到新的姿态向量。
   需要注意的是,由于计算精度问题,上述计算进行多次以后会存在舍入误差,使三个姿态向量不再垂直。为了解决这个问题需要在旋转之前对三个向量进行归一化。这里的归一化不是对三个向量各自归一,而是按照下述方式进行:
D3DXVec3Normalize(&vLook,&vLook);
D3DXVec3Cross(&vRight,&vUp,&vLook);
D3DXVec3Normalize(&vRight,&vRight);
D3DXVec3Cross(&vUp,&vLook,&vRight);
D3DXVec3Normalize(&vUp,&vUp);
可以看到是通过向量单独归一和叉乘的方式进行,既保证向量归一,又保证垂直。
   matLocal矩阵的保存形式如下:第一行是Right,第二行是Up,第三行是Look,第四行是Position:
m_pObjects[0].matLocal._11 = vRight.x;
m_pObjects[0].matLocal._12 = vRight.y;
m_pObjects[0].matLocal._13 = vRight.z;
m_pObjects[0].matLocal._21 = vUp.x;
m_pObjects[0].matLocal._22 = vUp.y;
m_pObjects[0].matLocal._23 = vUp.z;
m_pObjects[0].matLocal._31 = vLook.x;
m_pObjects[0].matLocal._32 = vLook.y;
m_pObjects[0].matLocal._33 = vLook.z;
m_pObjects[0].matLocal._41 = vPos.x;
m_pObjects[0].matLocal._42 = vPos.y;
m_pObjects[0].matLocal._43 = vPos.z;
   下面我们把上述变换过程总结一下:
确定旋转角度和旋转轴。 
取出当前的vRight,vLook,vUp,vPos向量; 
对三个向量进行归一化; 
利用D3DMatrixRotationAxis(D3DXMatrix* mat,D3DXVector* vAxis,FLOAT fRad)产生旋转矩阵; 
利用D3DXVectorTransformCoord(D3DXVector* vNew,D3DXVector* vOld,D3DXMatrix* mat)对当前的vRight,vLook,vUp向量进行变换,得到新的vRight,vLook,vUp向量。 
移动位置,获得新的vPos; 
将新的vRight,vLook,vUp,vPos向量设置到matLocal中。
----------------------------

上边的表示方法我们看到要7个过程,这略微有些复杂,那么下面我们来看另外一种简洁的计算方法-四元数(Quaternion)。

  我们先对比一下实现的差别,然后再具体解释API的含义。

 确定旋转角度和旋转轴。 
利用D3DXQuaternionRotationYawPitchRoll(D3DXMatrix* mat,Float fYaw,FLOAT fPitch,FLOAT fRoll)的到变换矩阵。 
把上述得到的矩阵同matLocal相乘得到新的matLocal; 
做位置的变换。
   四元数的原理有点复杂,由于速成关系我也没有怎么看,只是知道可以简单想象成一个向量加上一次旋转,具体的运算推导有机会再研究吧。但这个东西用途的确很广泛,因此被作为一种专门的方法被D3D介绍。

   上边只用到了一个API,那就是D3DXQuaternionRotationYawPitchRoll(D3DXMatrix* mat,Float fYaw,FLOAT fPitch,FLOAT fRoll),给定绕三个轴的旋转角度,返回一个变换矩阵。

-----------------------------

   下边看一下观察变换,观察矩阵同物体定位矩阵唯一不同的就是其存储方式,它采取列向量的存储方式。相机的各种变换同物体的变换没有任何不同,最后也是得到一个矩阵,只是D3D提供了一个根据视点位置,相机朝向和向上方向构造矩阵的函数:D3DXMatrixLookAtLH(D3DXMatrix* mat,D3DXVECTOR3* pEye,D3DXVECTOR3* pAt,D3DXVECTOR3* pUp),省着自己算了。最后用m_pd3Device->SetTransform(D3DTS_VIEW,&mat)设置一下就可以了。

   这里需要注意的是D3DXMatrixLookAtLH()只适合于简单的头罩式显示或者视点跟随,对于具有复杂旋转的飞行模拟器这类相机最好还是自己来算。计算的方式同前边介绍的物体变换的方式一样,也有两种方式,一种是复杂的7步变换,一种是简单的四元数变换。最后将得到的向量按照列向量的形式赋给视矩阵,再利用SetTransform()设置一下就好了。这实际上是一种自己维护相机的方式。

------------------------------

下面看一下投影变换。提到投影就会想到视锥,就会有视域角(FOV-field of view)、宽高比(aspect)和远近裁减面这四个参数。在D3D里边可以利用D3DXMatrixPerspectiveFoVLH(D3DXMATRIX* pOut,FLOAT fovY,FLOAT Aspect,FLOAT zn,FLOAT zf),通过给定的四个参数获得投影矩阵,然后用m_pd3Device->SetTranform(D3DTS_PROJECTION,&pOut)来设置投影矩阵即可。

-------------------------------
   视口的使用上次已经说过了,下面就看一下深度缓冲的使用。
   在框架里边使用深度缓冲只要让m_d3dEnumeration.AppUsesDepthBuffer = TRUE.然后在每一帧绘制前用m_pd3Device->Clear()方法清空缓冲区。
   HRESULT Clear(
                 DWORD Count,//矩形数量
                 const D3DRECT *pRects,//矩形指针
                 DWORD Flags,//要清除的缓冲类型
                 float Z,//Z缓冲设置的值
                 DWORD Stencil)//模板缓冲设置的值
   书中还讲了一个深度缓冲精度影响渲染质量的问题,为了达到无错误的稳定效果可以是用W缓冲器。方法如下:
   m_pd3Device->SetRenderState(D3DTS_ZNABLE,D3DZB_USEW).
但是这需要硬件的支持,为了稳妥起见还是使用Z缓冲比较好。
-------------------------------
  总结来说,D3D要设置的矩阵分为三种:除了上次提到的世界坐标矩阵,其实我理解也就是openGL里边对应的模型视图矩阵中的模型矩阵,还有视矩阵和投影矩阵。它们的设置函数都是pDeviceObject->SetTransform(),只不过参数不同而已。所有的其他函数也好,表示也好最终都是为了获得这三个矩阵,这让我们拨开云雾见太阳,只要心中挂念这矩阵就可以了。