我的directX编程学习(4)-坐标变换初步
今天开始看动画初步,其实主要就是坐标变换。无论对于directX也好,对于openGL也好,坐标变换都是做基本最重要的部分。所以今天一定要好好学习学习。
先看一下D3D的矩阵表示形式:
m._11 m._12 m._13 m._14 ux uy uz 0
m._21 m._22 m._23 m._24 = vx vy vz 0
m._31 m._32 m._33 m._34 wx wy wz 0
m._41 m._42 m._43 m._44 tx ty tz 1
下面看一下D3D需要构造的几个基本矩阵:
1,平移矩阵
1 0 0 0
0 1 0 0
0 0 1 0
tx ty tz 1
平移矩阵可以由函数:VOID D3DMatrixTranslation(D3DMATRIX* m,FLOAT tx,FLOAT ty,FLOAT tz)来构造。
2,旋转矩阵
以绕Y轴旋转为例,矩阵形式如下:
cosR 0 -sinR 0
0 1 0 0
sinR 0 cosR 0
0 0 0 1
以上矩阵可以通过类似VOID D3DMatrixRotationY(D3DMATRIX* m,FLOAT r)来获得。同样可以得到绕X,Z轴旋转的矩阵。
3,缩放矩阵
sx 0 0 0
0 sy 0 0
0 0 sz 0
0 0 0 1
可以通过D3DMATRIX* D3DMatrixScaling(D3DMATRIX *pOut,FLOAT sx,FLOAT sy,FLOAT sz)来获得。
得到上述矩阵以后,可以通过矩阵乘法来累积变换,乘法形式同线性代数中所讲一样,不详述。调用形式如下:D3DMATRIX* D3DMatrixMultiply(D3DMATRIX *pOut,D3DMATRIX *pM1,D3DMATRIX *pM2).其中返回值同pOut值相同。
在C++中由于利用函数重载,还可以写成:pOut = pM1 * pM2的形式,当然也可以连乘:pOut = pM1 * pM2 * pM3.
获得了变换矩阵以后,要对顶点起作用,需要利用m_pDevice->SetTransform(D3DTS_WORLD,&m_matWorld)来设置。当然可以将D3DTS_WORLD换成D3DTS_VIEW,D3DTS_PROJECTION来设置视矩阵和投影矩阵。
在C++中由于利用函数重载,还可以写成:pOut = pM1 * pM2的形式,当然也可以连乘:pOut = pM1 * pM2 * pM3.
获得了变换矩阵以后,要对顶点起作用,需要利用m_pDevice->SetTransform(D3DTS_WORLD,&m_matWorld)来设置。当然可以将D3DTS_WORLD换成D3DTS_VIEW,D3DTS_PROJECTION来设置视矩阵和投影矩阵。
下面看一个实际应用的例子:
HRESULT CMyD3DApplication::FrameMove()
{
// rotates the object about the y-axis
D3DXMATRIX matRotY;
D3DXMATRIX matRotZ;
D3DXMatrixRotationY( &matRotY, m_fTime * 0.5f);
D3DXMatrixRotationZ( &matRotZ, m_fTime * 1.5f);
D3DXMATRIX matTrans;
D3DXMatrixTranslation(&matTrans, 0.0f, 0.0f, 0.0f);
HRESULT CMyD3DApplication::FrameMove()
{
// rotates the object about the y-axis
D3DXMATRIX matRotY;
D3DXMATRIX matRotZ;
D3DXMatrixRotationY( &matRotY, m_fTime * 0.5f);
D3DXMatrixRotationZ( &matRotZ, m_fTime * 1.5f);
D3DXMATRIX matTrans;
D3DXMatrixTranslation(&matTrans, 0.0f, 0.0f, 0.0f);
m_pd3dDevice->SetTransform( D3DTS_WORLD, &(matRotY * matRotZ * matTrans));
return S_OK;
}
}
我们用FrameMove()函数来制作动画,循环播放。我们只需要调用相应函数获得矩阵,然后乘起来,设置一下就可以了。
再看一小段代码:
// Each viewport fills a quarter of the window
m_RViewport.Width = MainViewport.Width / 2;
m_RViewport.Height = MainViewport.Height / 2;
m_RViewport.Y = m_SRTViewport.Y = 0;
m_RViewport.X = m_TRViewport.X = 0;
// Set the full Z range for each viewport
m_RViewport.MinZ = 0.0f;
m_RViewport.MaxZ = 1.0f;
m_pd3dDevice->SetViewport(&m_RViewport);
m_matWorld = RotationMatrix1;
m_pd3dDevice->SetTransform(D3DTS_WORLD, &m_matWorld);
m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,
0,
0,
4, // number of vertices
0,
2); // number of primitives
我们只要把已经做好的矩阵设置成当前世界坐标矩阵,然后依次绘制图元就可以了。
从这个例子我们也可以想象出d3d也存在着类似于openGL那样的一个保存当前状态的自动机。
上边的代码中我们也看到了使用视口的例子,通过设置不同视口的位置和大小,我们可以在屏幕上显示出不同的内容,书中就是使用四个视口分别展示了四种不同的变换。
再看一小段代码:
// Each viewport fills a quarter of the window
m_RViewport.Width = MainViewport.Width / 2;
m_RViewport.Height = MainViewport.Height / 2;
m_RViewport.Y = m_SRTViewport.Y = 0;
m_RViewport.X = m_TRViewport.X = 0;
// Set the full Z range for each viewport
m_RViewport.MinZ = 0.0f;
m_RViewport.MaxZ = 1.0f;
m_pd3dDevice->SetViewport(&m_RViewport);
m_matWorld = RotationMatrix1;
m_pd3dDevice->SetTransform(D3DTS_WORLD, &m_matWorld);
m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,
0,
0,
4, // number of vertices
0,
2); // number of primitives
我们只要把已经做好的矩阵设置成当前世界坐标矩阵,然后依次绘制图元就可以了。
从这个例子我们也可以想象出d3d也存在着类似于openGL那样的一个保存当前状态的自动机。
上边的代码中我们也看到了使用视口的例子,通过设置不同视口的位置和大小,我们可以在屏幕上显示出不同的内容,书中就是使用四个视口分别展示了四种不同的变换。