第一人称视角控制,就像quake一样用鼠标控制方向,用键盘控制左右前后。鼠标和键盘用directinput控制输入。 首先,我们可以知道d3d的view矩阵有三个组成部分,分别是三个向量:眼睛所在点、眼看着的点、向上的方向。 所以,我们首先定义三个向量: D3DXVECTOR3 VDot,VAtPoint,VUp; 赋予初值: VDot=D3DXVECTOR3( 2.0f, 0.0f, 2.0f ); VAtPoint=D3DXVECTOR3( 0.0f, 0.0f, 0.0f ); VUp=D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); 输入到VIEW矩阵matView: void SetView() { D3DXMatrixLookAtLH( &matView,&VDot, &VAtPoint, &VUp ); } 下面就可以开始做键盘控制前进、后退、左移、右移了:我们可以看到在这些控制中,VUp向量是不可以变化的,否则就会有斜着看的效果,只要同时控制VDot和VAtPoint两点的位置就可以了。 由上图,a点就是VDot,b点就是VPoint,ac就是VUp向量。首先,我们计算前进后退:前进后退实际上就是沿着ab的方向同时移动a点和b点: 第一步,计算向量ab: D3DXVec3Subtract(&ab,&VAtPoint,&VDot); 第二步,计算移动的方向和步长: D3DXVec3Normalize(&pOut2,&ab); pOut2.x*=u; pOut2.y*=u; pOut2.z*=u; 第三步,将移动的位置加到a和b两点中去,就可得到新的前后位置。 pOut=VDot; D3DXVec3Add(&VDot,&pOut,&pOut2); pOut=VAtPoint; D3DXVec3Add(&VAtPoint,&pOut,&pOut2);//*/ SetView(); 接下来,我们计算左右移动,实际上就是沿着abc面的法线n同时移动a和b点: 第一步,计算abc面的法线向量n:D3DXVec3Cross(&pOut,&ab,&ac); 其它步骤同上: D3DXVec3Normalize(&pOut2,&pOut); pOut2.x*=u;pOut2.y*=u;pOut2.z*=u; pOut=VDot; D3DXVec3Add(&VDot,&pOut,&pOut2); pOut=VAtPoint; D3DXVec3Add(&VAtPoint,&pOut,&pOut2); SetView(); 接下来的鼠标控制方向就不是那么简单了,它涉及到围绕空间的轴旋转空间某点,简单来说这里就是固定a点,使b点绕经过a点的一条轴线旋转: 我们把方向分为水平旋转和垂直旋转,其它的方向都是这两个方向的叠加。要绕任意轴旋转变换,我们要知道旋转轴在空间的一点(VDot)和其方向数(a,b,c)(注意这里的abc和上面的不同,这里是数值而不是点),就可以求出变换矩阵。 首先,是水平方向旋转,这是VAtPoint绕VUp旋转的结果: 方向数必须是标准化的,即是长度为1。 D3DXVec3Normalize(&pOut,&ac); a=pOut.x;b=pOut.y;c=pOut.z; v=(float)sqrt(c*c+b*b); 把VDot点移至原点: R=D3DXMATRIX(1,0,0,0, 0,1,0,0, 0,0,1,0, -VDot.x,-VDot.y,-VDot.z,1); //D3DXMatrixMultiply(&R,&R2,&RT); R2=R; 把现在的ab旋转至ZXO面,原来的变换矩阵是这样的: D3DXMATRIX(1,0,0,0, 0,cos(j1),sin(j1),0, 0,-sin(j1),cos(j1),0, 0,0,0,1); 但因为cos(j1)=c/v;sin(j1)=b/v;所以变为下面的矩阵 RT=D3DXMATRIX(1,0,0,0, 0,c/v,b/v,0, 0,-b/v,c/v,0, 0,0,0,1); D3DXMatrixMultiply(&R,&R2,&RT);R2=R; 同理: cos(j2)=v/|OA|=v/1=v (OA已经标准化了) sin(j2)=-a/|OA|=a;所以得到下面的矩阵: RT=D3DXMATRIX(v,0,a,0, 0,1,0,0, -a,0,v,0, 0,0,0,1); D3DXMatrixMultiply(&R,&R2,&RT);R2=R; 这时我们就可以使VAtPoint绕VUp旋转变为在新坐标系中绕Z轴转u角(弧度表示) RT=D3DXMATRIX((float)cos(u),(float)sin(u),0,0, -(float)sin(u),(float)cos(u),0,0, 0,0,1,0, 0,0,0,1); D3DXMatrixMultiply(&R,&R2,&RT);R2=R; 接下来进行逆变换; RT=D3DXMATRIX(v,0,-a,0, 0,1,0,0, a,0,v,0, 0,0,0,1); D3DXMatrixMultiply(&R,&R2,&RT);R2=R;
RT=D3DXMATRIX(1,0,0,0, 0,c/v,-b/v,0, 0,b/v,c/v,0, 0,0,0,1); D3DXMatrixMultiply(&R,&R2,&RT);R2=R;
RT=D3DXMATRIX(1,0,0,0, 0,1,0,0, 0,0,1,0, VDot.x,VDot.y,VDot.z,1); D3DXMatrixMultiply(&R,&R2,&RT); 这时得到的R就是VAtPoint绕VUp旋转的变换矩阵 D3DXVec3Transform(&Vtemp,&VAtPoint,&R); VAtPoint.x=Vtemp.x;VAtPoint.y=Vtemp.y; VAtPoint.z=Vtemp.z; SetView(); 而垂直方向的旋转原理上是一样的,但不是绕VUp旋转,而是绕abc面的法线旋转,所以开始应该先计算法线并标准化: D3DXVec3Cross(&pOut2,&ab,&VUp); D3DXVec3Normalize(&pOut,&pOut2); 剩下的同上,但是为了限制向上和向下的范围(0<J<180,即到达顶端或者到达最底时不要再向另一方向旋转),在前面加上判定向量ab与VUp的夹角: s1=D3DXVec3Length(&ab)*D3DXVec3Length(&VUp); s1=(float)acos(D3DXVec3Dot(&ab,&VUp)/s1); if(u>0) { if(s1<=0.018) return; }//1度 else if(s1>=3.124) return;//179度 这样,第一人称视角的矩阵控制就完成了。 |