今天想用D3D实现一个简单的效果:先画一个立方体,然后鼠标左键使之能够沿Y轴旋转,鼠标右键使之能够沿Z轴旋转。第一个功能倒是实现了,但是第二个功能却有些毛病。
代码如下:
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 函数中:
……………
case WM_LBUTTONDOWN:
g_iRotateY += 20;
Render();
ValidateRect(hWnd, NULL);
return 0;
case WM_RBUTTONDOWN:
g_iRotateZ += 20;
Render();
ValidateRect(hWnd, NULL);
return 0;
……………
VOID SetupMatrices() 函数中:
……………
FLOAT angleY = ANGLE_TO_RADIAN(g_iRotateY);
FLOAT angleZ = ANGLE_TO_RADIAN(g_iRotateZ);
// 定义世界变换矩阵(World Transformation Matrix)
D3DXMATRIX matWorld;
D3DXMatrixTranslation(&matWorld, 0, 0, 0);// 1
D3DXMatrixRotationY(&matWorld, angleY); // 2
D3DXMatrixRotationZ(&matWorld, angleZ); // 3
g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);
……………
注意到蓝色字体部分,为什么执行完这两句后只有一句起作用呢?并且每次都是第二句话起作用(意思是说:当我把第2句话放在第3句话的下面时,就只有绕Y轴旋转,即鼠标左键起作用,右键无效;如果按代码中所示,则只有右键起作用,左键无效)。乍一看,好像没有错误啊,我把矩阵的指针传进去,然后对我的矩阵进行操作,结果由这个矩阵带出来。当我执行第2句时,矩阵发生变化,然后将这个变换后的矩阵再进行第二次操作,即执行第3句话,然后理所当然的应该在刚刚已经变化后的矩阵上进行变换。没有错!!!可恰恰就是错了,请注意:我们在使用这个矩阵matWorld的时候,并没有对其进行初始化,然后就直接用了,如果这个想法成立,那么上面的结果应该就不会错。那么我们可以看一看D3DXMATRIX的构造函数:
#ifdef __cplusplus
typedef struct D3DXMATRIX : public D3DMATRIX
{
public:
D3DXMATRIX() {};
D3DXMATRIX( CONST FLOAT * );
D3DXMATRIX( CONST D3DMATRIX& );
D3DXMATRIX( CONST D3DXFLOAT16 * );
D3DXMATRIX( FLOAT _11, FLOAT _12, FLOAT _13, FLOAT _14,
FLOAT _21, FLOAT _22, FLOAT _23, FLOAT _24,
FLOAT _31, FLOAT _32, FLOAT _33, FLOAT _34,
FLOAT _41, FLOAT _42, FLOAT _43, FLOAT _44 );
显然,我们并没有发现默认构造函数将矩阵初始化(矩阵的初始化肯定是单位化)。而我们程序中的结果又是只有最后的一个变换才起到作用,那么我们可以推测,是不是在变换中我们进行了初始化,并进行了变换。推测是成立的,我们三次都是对同一个矩阵进行操作:
第1句:将矩阵matWorld进行单位化,然后再对矩阵进行平移操作,操作向量为(0, 0, 0);
第2句:将矩阵matWorld进行单位化,然后再对矩阵进行绕Y轴旋转操作,旋转角度为angleY;
第3句:将矩阵matWorld进行单位化,然后再对矩阵进行绕Z轴旋转操作,旋转角度为angleZ;
由此看出,我们起作用的实际上只有一句,即第3句。
查看函数原型:
D3DXMATRIX * D3DXMatrixTranslation(
D3DXMATRIX * pOut,
FLOAT x,
FLOAT y,
FLOAT z
);
D3DXMATRIX * D3DXMatrixRotationY(
D3DXMATRIX * pOut,
FLOAT Angle
);
……………
在这一类矩阵操作函数中都要注意上面说的这个问题,即:先将矩阵单位化,再对这个单位矩阵进行操作。在D3D的API函数中,把矩阵单位化进行了隐藏。
怎么修改:
设置多个矩阵,最后让这些矩阵相乘,然后进行设置。
代码如下:
D3DXMATRIX matWorld;
D3DXMATRIX matRotationY;
D3DXMATRIX matRotationZ;
D3DXMatrixTranslation(&matWorld, 0, 0, 0);
D3DXMatrixRotationY(&matRotationY, angleY);
D3DXMatrixRotationZ(&matRotationZ, angleZ);
D3DXMatrixMultiply(&matWorld, &matRotationY, &matRotationZ);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);