Game Programming with DirectX -- 04[动起来更精彩]
第四集 动起来更精彩
左看, 右看, 上看, 都喜欢; 老板, 能不能把房子倒过来让我看看? 老板(汗!)
这一集我们讲讲解析几何和高等代数中的部分知识, 用来旋转模型及移动视口. 对与这部分数学知识掌握的只需了解一下D3DX提供的相映函数即可.
4.1 向量
4.1.1 空间向量
空间向量二要素 : 长度(模)和方向; 我们使用最广的是单位向量, 对单位向量 v 有
| v | = sqrt( v x * v x + v y * v y + v z * v z) = 1
空间向量在DirectX Graphics中以D3DVECTOR结构表示, 但我们实际用的最多的是封装了简单向量运算的D3DXVECTOR3, 对于向量的加减, 数乘和等于或不等运算就变的很简单.
在DirectX Graphics中, 常用的向量运算函数有,
a. 求模 FLOAT D3DXVec3Length(CONST D3DXVECTOR3 * pV);
b. 转化为单位向量
D3DXVECTOR3* D3DXVec3Normalize(D3DXVECTOR3 * pOut,
CONST D3DXVECTOR3 * pV);
c. 点乘(数量积)
FLOAT D3DXVec3Dot(CONST D3DXVECTOR3 * pV1,
CONST D3DXVECTOR3 * pV2);
d. 叉乘(向量积)
D3DXVECTOR3 * D3DXVec3Cross(D3DXVECTOR3 * pOut,
CONST D3DXVECTOR3 * pV1,
CONST D3DXVECTOR3 * pV2);
e. 最值
D3DXVECTOR3 * D3DXVec3Maximize(D3DXVECTOR3 * pOut,
CONST D3DXVECTOR3 * pV1,
CONST D3DXVECTOR3 * pV2);
D3DXVECTOR3 * D3DXVec3Minimize(D3DXVECTOR3 * pOut,
CONST D3DXVECTOR3 * pV1,
CONST D3DXVECTOR3 * pV2);
f. 缩放
D3DXVECTOR3 * D3DXVec3Scale(D3DXVECTOR3 * pOut,
CONST D3DXVECTOR3 * pV,
FLOAT s);
向量主要是在有光照效果的情况下使用, 在求三角形的法向量时用的最多, 只要了解向量的基本运算就可以了.
4.2 矩阵
4.2.1 矩阵的表示
| a11 a12 ... a1m |
| a21 a22 ... a2m |
A = | ... ... ... ... | = aij( i = 1, 2, ..., n; j = 1, 2, ..., m)
| an1 an2 ... anm |
(当 n = m 时, 称A为n阶矩阵).
前面所讲的向量和坐标都可用矩阵表示,
| Vx |
P = [ Px, Py, Pz, Pw ], v = | Vy |
| Vz |
4.2.2 矩阵的基本运算,
(a). 加法
| a11 a12 a13 | | b11 b12 b13 |
A = | a21 a22 a23 | B = | b21 b22 b23 |
| a31 a32 a33 | | b31 b32 b33 |
| a11 + b11 a12 + b12 a13 + b13 |
A + B= | a21 + b21 a22 + b22 a23 + b23 | (A和B的行列必须相同)
| a31 + b31 a32 + b32 a33 + b33 |
(b). 减法
A - B = A + (-B) (A和B的行列必须相同)
(c). 数乘
| r*a11 r*a12 r*a13 |
rA = | r*a21 r*a22 r*a23 | (r为一实数)
| r*a31 r*a32 r*a33 |
(d). 乘法
| c11 c12 | | d11 d12 |
C * D = | c21 c22 | * | d21 d22 |
| c11*d11 + c12*d21 c11*d12 + c12*d22 |
= | c21*d11 + c22*d21 c21*d12 + c22*d22 | (C的列数必须等于D的行数)
其中 C * D <> D * C
4.2.3 特殊矩阵
(a). 单位矩阵I
| 1 0 | | 1 0 0 | | 1 0 0 0 | | 1 |
| 0 1 | | 0 1 0 | | 0 1 0 0 | | 1 |
| 0 0 1 | | 0 0 1 0 | | ... |
| 0 0 0 1 | | 1|n * n
I * M = M * I = M
(b). 转置矩阵
| a11 a12 ... a1m | | a11 a21 ... an1 |
| a21 a22 ... a2m | | a11 a22 ... an2 |
A = | ... ... ... ... | , A' = | ... ... ... ... |
| an1 an2 ... anm | | a1m a2m ... anm |
A' 为A的转置矩阵; 如果A' = A, A为对称矩阵; 如果A' = - A, A为反对称矩阵
(c). 逆矩阵
| a11 a12 ... a1m |
| a21 a22 ... a2m |
A = | ... ... ... ... |
| an1 an2 ... anm |
如果A * B = B * A = I, 称B为A的逆矩阵, 并不是所有的矩阵都有逆矩阵的.
4.2.4 DirectX Graphics中的矩阵
DirectX Graphics中, 矩阵以D3DMATRIX结构表示, 同样实际用的最多的是封装了简单矩阵运算的D3DXMATRIX, 对于矩阵的加减, 数乘和等于或不等运算就变的很简单.
对于上面的特殊矩阵对应的函数是,
D3DXMATRIX * D3DXMatrixIdentity(D3DXMATRIX * pOut);
D3DXMATRIX * D3DXMATRIXTranspose(D3DXMATRIX * pOut,
CONST D3DXMATRIX * pM);
D3DXMATRIX * D3DXMATRIXInverse(D3DXMATRIX * pOut,
FLOAT * pDeterminant,
CONST D3DXMATRIX * pM);
4.2.5 DirectX Graphics中矩阵函数的作用
DirectX Graphics中矩阵运算主要集中在模型转换(从物体局部坐标系到世界坐标系), 视口转换(世界坐标系到摄影机坐标系), 投影转换(摄影机坐标系到屏幕坐标系).
其中以模型转换中用到的最多, DirectX Graphics中默认是一4*4的单位矩阵, 即局部坐标系到世界坐标系的转换对坐标原点及各坐标轴不作任何的改动.
(a). 如果各模型在定义时表示的坐标值就是参考世界坐标系原点的(如上面例子game2中各四边形的坐标), 那么各模型的局部坐标系已经等同于世界坐标系了, 这时模型转换就是世界坐标系W = I * M(局部坐标系), 这时可以省去模型转换(使用默认值).
(b). 如果各模型在定义时表示的坐标值是参考局部坐标系原点的(如以后例子game7中各模型的坐标), 如果这时在模型转换时不作相应的转换, 那么所有的模型在世界坐标系中都会重叠在坐标原点附近, 所以这时我们必须明确的告诉DirectX Graphics各模型的转换矩阵. 这主要是在使用复杂的模型Mesh时必不可少的步骤.
这一集的例子中, 各模型的坐标是根据(a)的方式来表示的, 大家有兴趣可以把它改成用(b)的方式来表示, 在绘制时, 不要忘记设置各模型的转换矩阵.
4.2.6 矩阵函数
(a). 位移
D3DXMATRIX * D3DXMATRIXTranslation(D3DXMATRIX * pOut,
FLOAT x,
FLOAT y,
FLOAT z);
实际对任一顶点P(Px, Py, Pz, 1)或向量V(Vx, Vy, Vz, 1), 都乘以上面函数产生的矩阵来进行位移, 这个矩阵为
| 1 0 0 0 |
| 0 1 0 0 |
T = | 0 0 1 0 |
| x y z 1 |
例如对齐次坐标点O(0, 0, 0, 1), 我们想让它在x轴向正方向移2个单位, y轴向正方向移4个单位, z轴向负方向移2个单位, 则它的位移矩阵 如下所示 , 如图4.1.
D3DXMATRIX m;
D3DXMATRIXTranslation(&m, 2, 4, -2);
图4.1
| 1 0 0 0 |
| 0 1 0 0 |
T = | 0 0 1 0 |
| 2 4 -2 1 |
| 1 0 0 0 |
| 0 1 0 0 |
O * T = (0, 0, 0, 1) * | 0 0 1 0 | = (2, 4, -2, 1)
| 2 4 -2 1 |
(b) . 旋转
旋转常用的有 4 个
绕X轴旋转, 其中Angle为弧度
D3DXMATRIX * D3DXMatrixRotationX(D3DXMATRIX * pOut,
FLOAT Angle);
绕Y轴旋转, 其中Angle为弧度
D3DXMATRIX * D3DXMatrixRotationY(D3DXMATRIX * pOut,
FLOAT Angle);
绕Z轴旋转, 其中Angle为弧度
D3DXMATRIX * D3DXMatrixRotationZ(D3DXMATRIX * pOut,
FLOAT Angle);
绕自定义轴旋转, 其中Angle为弧度
D3DXMATRIX * D3DXMatrixRotationAxis(D3DXMATRIX * pOut,
CONST D3DXVECTOR3 * pV,
FLOAT Angle);
绕自定义轴旋转的旋转矩阵按具体向量值给出 , 比较复杂 , 我们不列出 ; 其余 3 个生成的旋转矩阵如下所示 , 其中 R 为弧度表示的旋转角度 .
| 1 0 0 0 |
| 0 cosR sinR 0 |
X(R) = | 0 -sinR cosR 0 |
| 0 0 0 1 |
| cosR 0 -sinR 0 |
| 0 1 0 0 |
Y(R) = | sinR 0 cosR 0 |
| 0 0 0 1 |
| cosR sinR 0 0 |
| -sinR cosR 0 0 |
Z(R) = | 0 0 1 0 |
| 0 0 0 1 |
例如对齐次坐标点P(4, 4, 0, 1), 我们想让绕x轴旋转30度, 则它的旋转矩阵 如下所示 , 如图4.2.
D3DXMATRIX m;
D3DXMatrixRotationX (&m, 0.5236);
图 4.2
| 1 0 0 0 |
| 0 0.886 0.5 0 |
X(0.5236) = | 0 -0.5 0.886 0 |
| 0 0 0 1 |
| 1 0 0 0 |
| 0 0.886 0.5 0 |
P * X(0.5236) = (4, 4, 0, 1) * | 0 -0.5 0.886 0 | = (4, 3.464, 2, 1)
| 0 0 0 1 |
(c) . 缩放
D3DXMATRIX * D3DXMatrixScaling(D3DXMATRIX * pOut,
FLOAT sx,
FLOAT sy,
FLOAT sz);
函数生成的缩放矩阵为 ,
| Sx 0 0 0 |
| 0 Sy 0 0 |
S = | 0 0 Sz 0 |
| 0 0 0 1 |
例如对上例中的齐次坐标点P(4, 4, 0, 1), x轴, y轴, z轴各缩短为原来的一半, 则它的 缩放 矩阵 如下所示 , 如图4.3.
D3DXMATRIX m;
D3DXMatrixScaling(&m, 0.5, 0.5, 0.5);
图 4.3
| 0.5 0 0 0 |
| 0 0.5 0 0 |
S = | 0 0 0.5 0 |
| 0 0 0 1 |
| 0.5 0 0 0 |
| 0 0.5 0 0 |
P * S = (4, 4, 0, 1) * | 0 0 0.5 0 | = ( 2, 2, 0, 1)
| 0 0 0 1 |
(d) . 建立摄影机坐标矩阵
下面两函数分别建立左手和右手摄影机坐标矩阵 ,
D3DXMATRIX * D3DXMATRIXLookAtLH(D3DXMATRIX * pOut,
CONST D3DXVECTOR3 * pEye,
CONST D3DXVECTOR3 * pAt,
CONST D3DXVECTOR3 * pUp);
D3DXMATRIX * D3DXMATRIXLookAtRH(D3DXMATRIX * pOut,
CONST D3DXVECTOR3 * pEye,
CONST D3DXVECTOR3 * pAt,
CONST D3DXVECTOR3 * pUp);
三个向量参数中, 第一个表示视点在世界坐标系中坐标, 第一个到第二个的向量就是视线的方向了, 第三个表示世界坐标系中y轴的正方向, 一般默认向上为世界坐标系中y轴的正方向, 用D3DXVECTOR3(0.0, 1.0, 0.0)表示.
例如建立一个 视点在(0, 0, -10), 看向世界坐标系原点(0, 0, 0), 世界坐标系中y轴的正方向朝上 , 调用方式如下 , 图4.4.
D3DXMATRIX mView;
D3DXMatrixLookAtLH(&mView,
&D3DXVECTOR3(0.0, 0.0, -10.0),
&D3DXVECTOR3(0.0, 0.0, 0.0),
&D3DXVECTOR3(0.0, 1.0, 0.0));
图4.4
(e) . 建立投影坐标矩阵
有两种类型的投影坐标矩阵, 正射投影和透视投影.
(1). 正射投影. 如图4.5
正射投影,又叫平行投影. 这种投影是视矩形平行管道, 也就是一个长方体. 正射投影的最大特点是无论物体距离摄影机多远, 投影后的物体大小尺寸不变. 这种投影通常用在建筑蓝图绘制和计算机辅助设计等方面, 这些行业要求投影后的物体尺寸及相互间的角度不变,以便施工或制造时物体比例大小正确.
图4.5
D3DXMATRIX * D3DXMatrixOrthoOffCenterLH(D3DXMATRIX * pOut,
FLOAT l,
FLOAT r,
FLOAT b,
FLOAT t,
FLOAT zn,
FLOAT zf);
D3DXMATRIX * D3DXMatrixOrthoOffCenterRH(D3DXMATRIX * pOut,
FLOAT l,
FLOAT r,
FLOAT b,
FLOAT t,
FLOAT zn,
FLOAT zf);
D3DXMATRIX * D3DXMatrixOrthoLH(D3DXMATRIX * pOut,
FLOAT w,
FLOAT h,
FLOAT zn,
FLOAT zf);
D3DXMATRIX * D3DXMatrixOrthoRH(D3DXMATRIX * pOut,
FLOAT w,
FLOAT h,
FLOAT zn,
FLOAT zf);
一般选择图中第二种方式, 参数少.
(1). 透视投影. 如图4.6
透视投影符合实际, 即离视点近的物体大, 离视点远的物体小, 远到极点即为消失.它是 视域四棱台 . 这个投影通常用于动画、视觉仿真以及其它许多具有真实性反映的方面.
图4.6
D3DXMATRIX * D3DXMatrixPerspectiveOffCenterLH(
D3DXMATRIX * pOut,
FLOAT l,
FLOAT r,
FLOAT b,
FLOAT t,
FLOAT zn,
FLOAT zf);
D3DXMATRIX * D3DXMatrixPerspectiveOffCenterRH(
D3DXMATRIX * pOut,
FLOAT l,
FLOAT r,
FLOAT b,
FLOAT t,
FLOAT zn,
FLOAT zf);
D3DXMATRIX * D3DXMatrixPerspectiveLH(D3DXMATRIX * pOut,
FLOAT w,
FLOAT h,
FLOAT zn,
FLOAT zf);
D3DXMATRIX * D3DXMatrixPerspectiveRH(D3DXMATRIX * pOut,
FLOAT w,
FLOAT h,
FLOAT zn,
FLOAT zf);
D3DXMATRIX * D3DXMatrixPerspectiveFovLH(D3DXMATRIX * pOut,
FLOAT fovy,
FLOAT Aspect,
FLOAT zn,
FLOAT zf);
D3DXMATRIX * D3DXMatrixPerspectiveFovRH(D3DXMATRIX * pOut,
FLOAT fovy,
FLOAT Aspect,
FLOAT zn,
FLOAT zf);
一般选择图中第三种方式, 参数少且直观.
4.2.7 向量的矩阵转换
根据转换矩阵转换单个向量为齐次向量, w = 1
pV * pM = pOut = (x, y, z, 1)
D3DXVECTOR4 * D3DXVec3Transform(D3DXVECTOR4 * pOut,
CONST D3DXVECTOR3 * pV,
CONST D3DXMATRIX * pM);
根据转换矩阵转换含N个向量的数组为N个向量的齐次向量数组, Wn = 1
pV[n] * pM = pOut = (Xn, Yn, Zn, 1),
OutStride = sizeof(D3DXVECTOR4), VStride = sizeof(D3DXVECTOR3),
n = count of pV array
D3DXVECTOR4 * D3DXVec3TransformArray(D3DXVECTOR4 * pOut,
UINT OutStride,
CONST D3DXVECTOR3* pV,
UINT VStride,
CONST D3DXMATRIX* pM,
UINT n);
根据转换矩阵转换单个向量, w = 1
pV * pM = (x, y, z, 1), pOut = (x, y, z)
D3DXVECTOR3 * D3DXVec3TransformCoord(D3DXVECTOR3 * pOut,
CONST D3DXVECTOR3 * pV,
CONST D3DXMATRIX * pM);
根据转换矩阵转换含N个向量的数组, Wn = 1
pV[n] * pM = (Xn, Yn, Zn, 1), pOut = (Xn, Yn, Zn)
OutStride = sizeof(D3DXVECTOR3), VStride = sizeof(D3DXVECTOR3),
n = count of pV array
D3DXVECTOR3 * D3DXVec3TransformCoordArray(D3DXVECTOR3* pOut,
UINT OutStride,
CONST D3DXVECTOR3* pV,
UINT VStride,
CONST D3DXMATRIX* pM,
UINT n);
根据转换矩阵转换单个法向量, w = 0
pV * pM = (x, y, z, 0), pOut = (x, y, z)
D3DXVECTOR3 * D3DXVec3TransformNormal(D3DXVECTOR3 * pOut,
CONST D3DXVECTOR3 * pV,
CONST D3DXMATRIX * pM);
根据转换矩阵转换含N个法向量的数组, Wn = 0
pV[n] * pM = (Xn, Yn, Zn, 0), pOut = (Xn, Yn, Zn)
OutStride = sizeof(D3DXVECTOR3), VStride = sizeof(D3DXVECTOR3),
n = count of pV array
D3DXVECTOR3 * D3DXVec3TransformNormalArray(D3DXVECTOR3* pOut,
UINT OutStride,
CONST D3DXVECTOR3* pV,
UINT VStride,
CONST D3DXMATRIX* pM,
UINT n);
4.3 平面
平面可以用平面内的任意向量P和平面的法向量N表示, P DOT N = 0, 平面内的任意向量P可用平面中的两点表示, 其中选一特殊点P0和任意点P, 就有(P – P0) DOT N = 0,
N * P + d = 0(d = - N * P0), 所以平面也可以由平面法向量和一数值来确定.
确定一个点X和平面的关系, 只需将点的坐标代入上面的公式就能知道,
(1) N * X + d = 0, 点在面内
(2) N * X + d > 0, 点在面正半侧
(3) N * X + d < 0, 点在面负半侧
使用下面的函数来判断,
FLOAT D3DXPlaneDotCoord(CONST D3DXPLANE * pP,
CONST D3DXVECTOR3 * pV);
平面用的比较少, 在视域内可设置特殊的裁截面. DirectX Graphics中, 平面 以D3DXPLANE结构表示.
4.4 模型旋转的例子
4.4.1 代码更新
这一集的例子和上集的差不多, 上集中的例子所有的模型使用同样的模型转换矩阵, 这集的例子我们对每个模型使用不同的模型转换矩阵.
默认例子中使用的投影转换都是透视投影, 可以改成正射投影看看不同之出.
我们来看看game3的主要更新的代码(下载game3 project)
---------------------------------------------------------------
// direct9.cpp 中我们设置了些特殊的位移和缩放矩阵
HRESULT CD9Game::InitObject()
{
D3DXMatrixTranslation(&g_mMR20, 20.0, 0.0, 0.0);
D3DXMatrixTranslation(&g_mML20, -20.0, 0.0, 0.0);
D3DXMatrixTranslation(&g_mMU10, 0.0, 10.0, 0.0);
D3DXMatrixTranslation(&g_mMD10, 0.0, -10.0, 0.0);
D3DXMatrixTranslation(&g_mMR8, 8.0, 0.0, 0.0);
D3DXMatrixTranslation(&g_mML8, -8.0, 0.0, 0.0);
D3DXMatrixScaling(&g_mScaleUp, 2.0, 2.0, 2.0);
m_paObject[0] = new CD9Object(m_pD3DDev);
if ( m_paObject[0] == NULL )
{
return E_FAIL;
}
m_paObject[0]->SetPos(-20.0, 0.0, 0.0, 8.0, 8.0, 8.0);
m_paObject[1] = new CD9Object(m_pD3DDev);
if ( m_paObject[1] == NULL )
{
return E_FAIL;
}
m_paObject[1]->SetPos(-8.0, 0.0, 0.0, 8.0, 8.0, 8.0);
m_paObject[2] = new CD9Object(m_pD3DDev);
if ( m_paObject[2] == NULL )
{
return E_FAIL;
}
m_paObject[2]->SetPos(0.0, 10.0, 0.0, 8.0, 8.0, 8.0);
m_paObject[3] = new CD9Object(m_pD3DDev);
if ( m_paObject[3] == NULL )
{
return E_FAIL;
}
m_paObject[3]->SetPos(8.0, 0.0, 0.0, 8.0, 8.0, 8.0);
m_paObject[4] = new CD9Object(m_pD3DDev);
if ( m_paObject[4] == NULL )
{
return E_FAIL;
}
m_paObject[4]->SetPos(20.0, 0.0, 0.0, 8.0, 8.0, 8.0);
return S_OK;
}
// 我们为每个模型设置了不同的转换, 具体解释在后面的说明中
VOID CD9Game::Render()
{
D3DXMATRIX mWorld, mWorldX, mWorldY, mWorldZ;
D3DXMATRIX mWorld2, mWorld3, mWorld4, mWorld5;
if (m_nRot > MAXROT)
{
m_nRot = 0;
}
m_nRot++;
FLOAT rat = m_nRot * ROT;
D3DXMatrixRotationX(&mWorldX, rat);
D3DXMatrixRotationY(&mWorldY, rat);
D3DXMatrixRotationZ(&mWorldZ, rat);
D3DXMatrixRotationAxis(&mWorld, &D3DXVECTOR3(1.0, 1.0, 0.0), rat);
D3DXMatrixMultiply(&mWorld2, &g_mMR8, &mWorldY);
D3DXMatrixMultiply(&mWorld2, &mWorld2, &g_mML8);
D3DXMatrixMultiply(&mWorld3, &g_mMD10, &mWorldY);
D3DXMatrixMultiply(&mWorld3, &mWorld3, &mWorldX);
D3DXMatrixMultiply(&mWorld3, &mWorld3, &mWorldZ);
D3DXMatrixMultiply(&mWorld3, &mWorld3, &g_mMU10);
D3DXMatrixMultiply(&mWorld3, &mWorld3, &g_mScaleUp);
D3DXMatrixMultiply(&mWorld4, &g_mML8, &mWorldZ);
D3DXMatrixMultiply(&mWorld4, &mWorld4, &g_mMR8);
D3DXMatrixMultiply(&mWorld5, &g_mML20, &mWorld);
D3DXMatrixMultiply(&mWorld5, &mWorld5, &g_mMR20);
m_pD3DDev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
m_pD3DDev->BeginScene();
m_pD3DDev->SetTransform(D3DTS_WORLD, &mWorldX);
m_paObject[0]->Render();
m_pD3DDev->SetTransform(D3DTS_WORLD, &mWorld2);
m_paObject[1]->Render();
m_pD3DDev->SetTransform(D3DTS_WORLD, &mWorld3);
m_paObject[2]->Render();
m_pD3DDev->SetTransform(D3DTS_WORLD, &mWorld4);
m_paObject[3]->Render();
m_pD3DDev->SetTransform(D3DTS_WORLD, &mWorld5);
m_paObject[4]->Render();
m_pD3DDev->EndScene();
m_pD3DDev->Present(NULL, NULL, NULL, NULL);
}
// 设置摄影机坐标系
VOID CD9Game::SetCamera()
{
D3DXMATRIX mView;
D3DXMatrixLookAtLH(&mView, &D3DXVECTOR3(m_fx, m_fy,-64.0f),
&D3DXVECTOR3(0.0f, 0.0f, 0.0f),
&D3DXVECTOR3(0.0f, 1.0f, 0.0f));
m_pD3DDev->SetTransform(D3DTS_VIEW, &mView);
}
// 设置投影模式
VOID CD9Game::SetPerspective()
{
D3DXMATRIX mProj;
D3DXMatrixPerspectiveFovLH(&mProj, D3DX_PI/4, 1.0f, 1.0f, 512.0f);
//D3DXMatrixOrthoLH(&mProj, 64.0f, 64.0f, 1.0f, 512.0f);
m_pD3DDev->SetTransform(D3DTS_PROJECTION, &mProj);
}
---------------------------------------------------------------
4.4.2 说明
其实, 设置摄影机和投影在game1中就使用到了. 例子中5个模型绕不同的轴自转, 第一个绕X轴自转, 第二个绕Y轴自转, 第三个先X轴再Y轴最后Z轴自转, 同时把物体放大了一倍, 第四个绕Z轴自转, 最后的绕自定义的轴自转.
因为模型的坐标是参考世界坐标系建立的(这集的前面提到过), 而且模型是自转的, 所以我们必须作相映的坐标变换使模型能正确自转. 如果不这么做模型会变成绕轴旋转而不是自转了, 如图4.7.
图4.7
在转换中, 转换的矩阵的先后顺序很重要, 因为矩阵的乘法不可交换, 所以不同的先后顺序产生的效果是不同的, 一定要注意 -- 顺序.
第四集 小结
这一集我们学习了要进行DirectX Graphics 3D编程中的高等代数知识部分, 向量, 矩阵等, 例子是使用不同的模型转换矩阵来变换不同的模型.