在D3D中实现第一人称视角控制



原版文章在我主页有还有例子下载上我主页( border=0>http://www.udragon.net)吧 
这两天做了第人称视角控制就像quake样用鼠标控制方向用键盘控制左右前后鼠标和键盘用directinput控制输入

首先我们可以知道d3dview矩阵有 3个组成部分分别是 3个向量:眼睛所在点、眼看着点、向上方向

所以我们首先定义 3个向量:

D3DXVECTOR3 VDotVAtPoVUp;

赋予初值:

VDot=D3DXVECTOR3( 2.0f, 0.0f, 2.0f );
VAtPo=D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
VUp=D3DXVECTOR3( 0.0f, 1.0f, 0.0f );

输入到VIEW矩阵matView:

void SetView
{
    D3DXMatrixLookAtLH( &matView,&VDot, &VAtPo, &VUp );
}

下面就可以开始做键盘控制前进、后退、左移、右移了:我们可以看到在这些控制中VUp向量是不可以变化否则就会有斜着看效果只要同时控制VDot和VAtPo两点位置就可以了

 

由上图a点就是VDotb点就是VPoac就是VUp向量首先我们计算前进后退:前进后退实际上就是沿着ab方向同时移动a点和b点:

步,计算向量ab: D3DXVec3Subtract(&ab,&VAtPo,&VDot);

第 2步计算移动方向和步长: D3DXVec3Normalize(&pOut2,&ab);
pOut2.x*=u; pOut2.y*=u; pOut2.z*=u;

第 3步将移动位置加到a和b两点中去就可得到新前后位置
pOut=VDot;
D3DXVec3Add(&VDot,&pOut,&pOut2);
pOut=VAtPo;
D3DXVec3Add(&VAtPo,&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=VAtPo;
D3DXVec3Add(&VAtPo,&pOut,&pOut2);
SetView;

接下来鼠标控制方向就不是那么简单了它涉及到围绕空间轴旋转空间某点简单来说这里就是固定a点使b点绕经过a点条轴线旋转:

我们把方向分为水平旋转和垂直旋转其它方向都是这两个方向叠加要绕任意轴旋转变换我们要知道旋转轴在空间点(VDot)和其方向数(abc)(注意这里abc和上面区别这里是数值而不是点)就可以求出变换矩阵

首先是水平方向旋转这是VAtPo绕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;

这时我们就可以使VAtPo绕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就是VAtPo绕VUp旋转变换矩阵
D3DXVec3Transform(&Vtemp,&VAtPo,&R);
VAtPo.x=Vtemp.x;VAtPo.y=Vtemp.y;
VAtPo.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);
(u>0)
{
    (s1<=0.018)
        ;
}//1度
 (s1>=3.124)
    ;//179度

这样人称视角矩阵控制就完成了
Tags: 

延伸阅读

最新评论

发表评论