在平时玩的网游中,我们很明显的观察到摄像机在跟随人物移动,下面大致分析下原理,不过3D网游中具体是怎么实现的我就不知道了~
程序中的一个模型对应空间中的一个物体,在现实的世界中要xx的定位一个物体需要6个参数: 物体位置的三个分量(x,y,z)和3个欧拉角(偏航角yaw, 俯仰角pitch, 侧倾角roll).关于位置的三个分量大家很容易理解,下面说下3个欧拉角的具体意义
偏航角: 物体绕自身的Y轴(即上向量vUp,类似自己头顶所指的方向)旋转的角度
俯仰角: 物体绕自身的X轴(即右向量vRight,类似自己向侧边抬平自己右手所指的方向)旋转的角度
侧倾角: 物体绕自身的z轴(即前向量vLook,类似自己眼睛平视的方向)旋转的角度
一个模型在三维空间的中的位置和姿势都是通过世界矩阵来表示的,所以在程序中要控制一个物体的位置和姿态,实际就是把控制其状态的6个参数引入到世界矩阵中去
我们通过函数D3DXMatrixIndentity()将一个矩阵设置成单位矩阵,得到下列矩阵
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
其中{dy}列的前三个为vRight向量(1.0f, 0.0f, 0.0f),第二列的前三个为vUp向量(0.0f, 1.0f, 0.0f),第三列的前三个为vLook向量(0.0f, 0.0f, 1.0f),第四行的前三个为vPos向量(0.0f, 0.0f, 0.0f),这时的模型处在世界坐标系的原点,并且朝向和世界坐标系的三个坐标轴方向相同
要旋转一个物体,实际上就是vRight,vUp,vLook总的两个绕另一个旋转,比如你要让物体饶向四周旋转,实际就是vLook和vRight绕vUp旋转,当然每个向量的旋转在要借助旋转矩阵来完成,这可以通过D3DXMatrixRotationAxis()函数来得到,函数的原形如下
D3DXMATRIX *WINAPI D3DXMatrixRotationAxis(
D3DXMATRIX *pOut,
CONST D3DXVECTOR3 *pV,
FLOAT Angle
);
其中pOut为输出的矩阵, pV为一个待指定的旋转轴, 而Angle即为旋转的弧度
有的旋转矩阵后,我们可以借助D3DXVec3TransformCoord()函数来对向量进行变换,原形如下
D3DXVECTOR3 *WINAPI D3DXVec3Transform(
D3DXVECTOR3 *pOut,
CONST D3DXVECTOR3 *pV,
CONST D3DXMATRIX *pM
);
其中pOut为变换之后的向量, pV为变换之前的向量, pM为旋转矩阵
就以上面我们说的绕四周转为例,也就是偏航角的变化,下面用code来实现
D3DXMatrix matYaw; //变换矩阵
D3DXMatrixRotationAxis(&matYaw, &vUp, XX(旋转的弧度)); //得到旋转矩阵
D3DXVec3Transform(&vLook, &vLook, &matYaw); //得到变换后的vLook
D3DXVec3Transform(&vRight, &vRight, &matYaw); //得到变换后的vRight
看似完了,其实还没有,因为浮点数的计算存在精度问题,所以持续的旋转带来持续的计算导致累积的误差,最终会使模型的vLook,vUp,vRight不再互相垂直,为了避免这种情况,手动的为其复原:
D3DXVec3Normalize(&vLook, &vLook); //单位化vLook
D3DXVec3Cross(&vRight, &vUp, &vLook); //通过计算vUp与vLook的叉乘来得到与他们锤子的vRight
D3DXVec3Normalize(&vRight, &vRight); //单位化vRight
D3DXVec3Cross(&vUp, &vLook, &vRight); //通过计算vLook与vRight的叉乘来得到与他们锤子的vRight
D3DXVec3Normalize(&vUp, &vUp); //单位化vLook
由于位置不变,还是保持(0,0,0),现在就把向量再引入到世界变换矩阵中去
1 0 0 0 vRight.x vUp.x vLook.x 0
0 1 0 0 变成 vRight.y vUp.y vLook.y 0
0 0 1 0 vRight.z vUp.z vLook.z 0
0 0 0 1 vPos.x vPos.y vPos.z 1
现在就通过那一堆SetRenderState,然后渲染出来,搞定!
接下来是摄像机的跟随问题,其实很简单的,既然已经有了物体的vLook向量和vPos向量,我们只需要通过vPos - n * vLook就可以得到摄像机的位置,具体来讲物体当前的位置,加上N个与vLook方向向量相反的向量,N为正数因为你始终要在物体的背后,至于N是多少就得自己去试了,物体和摄像机要隔的越远,N就越大,否则隔的就近了,记的还要把物体的vRight赋给摄像机的vRight,不然可能在旋转到一定程度时出现错误,好了,大概就是这样了,我已经在被窝里写的快热死了- -