3D游戏编程入门(十七)设置变换矩阵让立方体变换
呼,趁热打铁,继续复习>_<真的好想玩玩啊,虽然不知道有什么好玩的,出去压马路太无聊了,恩,谁要是有什么比较不错的动漫,推荐下。
恩,立方体我们绘制出来了。接下来该把它放置到世界空间去了吧。
还记得第十章我在进行D3D基础名词解释时提到过的本地空间和世界空间,视图空间么。我们现在的所有模型绘制都是在一个本地空间中进行的,所以不存在任何的与其他物体的遮挡的情况出现,而且,恩,还不能旋转移动缩放等,现在我们就为这个立方体加上这些要素,有时间话争取今天给它帖上纹理,那就好看了,灯光材质嘛还要等明天。
恩,首先我们还要先讲些概念的东西。
我们可以回忆一下高中几何,我们确定一个面,可以依靠几种手段?三个点可以确定一个面,一条直线和直线外的一个点可以确定一个面,两条相交或平行的直线可以确定一个面。似乎就这样了吧.
呃,再补充个概念,假如我们有一个向量垂直于我们的平面,我们就称这条向量为平面的法线。
我们在D3D中确定平面可以这么写:
- 已知道了平面的法线向量n和平面上任意一点p,则获得一个确定的平面
D3DXPlaneFromPointNormal(
D3DXPLANE* pOut, //构造出的平面指针
const D3DXVECTOR3* pPoint, //点p
const D3DXVECTOR3* pNormal //法线n
);
- 当我们知道了平面上三个点,我们可以获得两个向量,再通过这两个向量的叉乘来获得垂直于他们的向量(为什么会获得?去看看我前面的日志),当一个向量同时垂直于两个相交的向量,那么这个向量则垂直于相交两条向量所在的面,这是我们高中已知的概念。等我们获得了平面法线向量后,又有其他的点,我们可以确定这个平面。
D3DXPlaneFromPoints(
D3DXPLANE* pOut, //构造出的平面
CONST D3DXVECTOR3* pV1, //点1
CONST D3DXVECTOR3* pV2, //点2
CONST D3DXVECTOR3* pV3, //点3
);
- 我们通过上两个公式获得的pOut是一个平面,它是由一个由四个数组成的数组。
D3DXPLANE x(a, b, c, d);
其中,a,b,c表示平面的法线向量,d是一个常量,它表示点(a,b,c)到平面的最小距离。
当我们获得平面后,我们需要将其标准化,对于平移变换矩阵,我们则需要得到它的逆转置矩阵。(这里真烦,我本想尽量避免来说明相关立体几何和线代的东西,看来还是逃不掉,下个章节就专门讲这东西了,现在大家就先死记一下吧,抱歉抱歉)
呃,获得逆转置矩阵和标准化平面的方法不需要我们自己手动写算法,D3D提供了一些函数,当然记住这些函数也可以做出一款游戏来,但是终究需要了解其原理的好,下一篇日志我将这些部分更加详细的讲解。现在大家先看下D3D提供的函数
D3DXPlaneNormalize(
D3DXPLANE* pOut, //标准化后的平面
CONST D3DXPLANE* pP //原平面
);
通过这个函数我们获得标准化平面,
D3DXPlaneTransform(
D3DXPLANE* pOut, //平移后的平面
CONST D3DXPLANE* pP, //原平面的标准化平面
CONST D3DXMATRIX* pM //平移矩阵的逆转置矩阵
);
通过这个函数我们可以获得一个矩阵的逆转置矩阵,这样我们就无需管矩阵中到底是什么样子的数据,仅用地址调用就可以了
- 当我们获得了变换矩阵后,我们对D3D设备使用我们的变换矩阵,函数为
g_pD3DDevice->SetTransform(D3DTS_WORLD, &matWorld);
这是通知我们的D3D设备,进行世界空间的变换,第一个参数为空间变换类型,第二个参数是我们的变换矩阵。
- 平移变换矩阵
D3DXMATRIX *D3DXMatrixTranslation(
D3DXMATRIX *pOut, //输出矩阵
FLOAT x, //x轴上的平移量
FLOAT y, // y轴上的平移量
FLOAT z // z轴上的平移量
);
- 缩放变换矩阵
D3DXMATRIX *D3DXMatrixScaling(
D3DXMATRIX *pOut, //输出矩阵
FLOAT sx, //x轴上的缩放量
FLOAT sy, // y轴上的缩放量
FLOAT sz // z轴上的缩放量
);
当我们各方向上缩放量相等时,图象将进行一个均匀的变换,当我们各个方向上缩放量不同时,我们的图象将会呈现出一种拉伸或者挤压的现象。
pOut就是我们实现该功能的所需要的变换矩阵指针,我们将它传入相应的函数中,就能实现相应的图象变换。
- 旋转变换矩阵
(1):绕X轴旋转:D3DXMatrixRotationX( D3DXMATRIX* pOut, FLOAT Angle);
(2):绕Y轴旋转:D3DXMatrixRotationY(参数同上)第一个参数为输出此变换矩阵的指针,第二个参数为旋转的角度
(3):绕Z轴旋转:D3DXMatrixRotationZ(参数同上)
(4):自定义旋转轴的旋转:D3DXMatrixRotationAxis( D3DXMATRIX* pOut,CONST D3DXVECTOR3* pV,FLOAT Angle);
其中第一个参数还是输出矩阵地址,第二参数是旋转轴的向量表示,第三个参数是旋转角度。
- 组合变换
若我们不仅需要旋转,还需要平移和缩放的话,我们可以使用矩阵的乘法来获得最终组合好的变换矩阵。
矩阵乘法函数为:
D3DXMatrixMultiply( D3DXMATRIX* pOut, //输出的组合变换矩阵
D3DXMATRIX* p1, //第一种变换矩阵
D3DXMATRIX* p2 //第二种变换矩阵
);
我们拿上次的立方体代码来说,我们需将下列代码替换其中的SetupRotation(),SetupCamera()两个方法就可以实现一个立方体的变换了。
SetupCamera()的改变是为了调整好我们的视角,避免图形变换出了我们的视野。
//设置旋转、移动和缩放,即设置世界变换
void SetupRotation()
{
D3DXMATRIX matWorld, matWorldX, matWorldY, matWorldZ;
D3DXMATRIX matScaling;
D3DXMATRIX matTranslation;
DWORD time = timeGetTime();
static int nScaling;
static bool bEnlarge;
// 分别绕X,Y,Z轴旋转。
D3DXMatrixRotationX(&matWorldX, time/400.0f);
D3DXMatrixRotationY(&matWorldY,time/400.0f);
D3DXMatrixRotationZ(&matWorldZ, time/400.0f);
float fK = 1.0f + nScaling/ 60.0f;
if (bEnlarge) {
nScaling++;
if (nScaling >= 60) bEnlarge = false;
} else {
nScaling--;
if (nScaling <= 0) bEnlarge = true;
}
// 进行缩放。
D3DXMatrixScaling(&matScaling, fK, fK, fK);
// 在X,Y方向平移。
D3DXMatrixTranslation(&matTranslation, nScaling/(FLOAT)3.5, -nScaling/(FLOAT)3.5, 0.0f);
// 把各种变化组合起来。
D3DXMatrixMultiply(&matWorld, &matWorldX, &matWorldY);
D3DXMatrixMultiply(&matWorld, &matWorld, &matWorldZ);
D3DXMatrixMultiply(&matWorld, &matWorld, &matScaling);
D3DXMatrixMultiply(&matWorld, &matWorld, &matTranslation);//进行平移
g_pD3DDevice->SetTransform(D3DTS_WORLD, &matWorld);
}
// 设置摄像机
void SetupCamera()
{
D3DXMATRIX matView;
D3DXMatrixLookAtLH(&matView, &D3DXVECTOR3(30.0f, 30.0f,30.0f), //摄像机的位置
&D3DXVECTOR3(0.0f, 0.0f, 0.0f), //摄像机的朝向
&D3DXVECTOR3(0.0f, -1.0f, 0.0f)); //摄像机的顶方向
g_pD3DDevice->SetTransform(D3DTS_VIEW, &matView);
}