[D3D] - DirectX SDK 2006学习笔记5——动画和矩阵变换
来源: http://www.cnblogs.com/fence/archive/2010/03/12/1683918.html
D3D中世界的运动是通过矩阵变化完成的。这里不打算讲数学知识,相关问题请参考计算机图形学书籍。 在D3D中矩阵 变换分为三种:世界变换,观察变换和投影变换。世界变换描述了物体本身的缩放,旋转和平移,也就是物体本身的运动;观察变换描述了一个观察者在场景中的位 置和朝向;投影变换描述了观察者可以看到内容的范围,类似这个范围类似于削去顶部的金字塔形状,该变换将透视法应用到一个3D场景中。 矩阵在D3D中是按语言分开定义的,如果用的是C语言,那么只能利用D3DMatrix;如果用的是C++,那么还可以用D3DXMatrix。它们的 差别就是后者利用了C++中的操作符重载的功能,例如矩阵乘法。这些矩阵都是4*4的,这样方便进行各种转换。另外还有一个D3DXMatrix16,这 是经过优化的版本,是以16位对齐的。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 );
} D3DXMATRIX;
一个单位矩阵可以这样定义: D3DXMatrix * m;
D3DMatrixIdentity( & m);
在世界变换中,有以下函数用于进行物体位置的变换:
- D3DXMatrixTranslation:平移矩阵。例如:D3DXMatrixTranslation(x, y, z)将物体平移到(x, y, z)
- D3DXMatrixRotationX:绕x轴旋转。类似的有绕Y和Z轴的旋转函数。例如:D3DXMatrixRotationX(&matrix,fAngle)。其中fAngle是旋转弧度。
- D3DXMatrixRotationAxis:绕任意轴旋转
- D3DXMatrixRotationQuaternion:绕四元组旋转。
- D3DXMatrixScaling:对物体进行缩放操作
D3DXVec3Cross( & vRight, & vUp, & vLook ); // 求Up和Look叉积来设定Right
D3DXVec3Normalize( & vRight, & vRight );
D3DXVec3Cross ( & vUp, & vLook, & vRight); // 求Look和Right叉积来设定Up
D3DXVec3Normalize( & vUp, & vUp ); 归一就是把向量单位化,计算公式为||A|| = sqrt(x*x + y*y + z*z)。
四元数: 四元数就是一个向量加上一次旋转。四元数将三维空间的旋转概念扩展到四维空间,这对于表示和处理3D中点的旋转很有用。四元数可以用于实现:
- 骨骼动画 ( skeletal animation )
- 反向动力学动画 ( inverse cinematics )
- 3D物理学
观察变换 观察变换通常用于描述一个观察者在场景中的位置和朝向。可以用照相机看场景的例子来描述这种变换。观察变换可以通过一个观察变换矩阵来表示。世界矩阵以 行的次序存储向量的朝向,而观察矩阵则以列的次序存储。D3D中提供了一种比较简单的观察矩阵获取方式,即调用D3DXMatrixLookAtLH。这 个函数必须要传进去三个向量,它们分别定义了照相机所在点eye,照相机拍摄物体位置at,和上方向量up。返回的矩阵第一列前三个值存储了up向量,第 二列的前3个值存储了Right向量,第三列的前3个值存储了Look向量。D3DXMatrixLookAtLH适合用于跟随式照相机,对于太空射击游 戏或者飞行模拟器就不适合了。解决办法有两个,一是将照相机绕向量旋转,二是使用四元数将照相机绕任意轴旋转。
Example 1 A plain’s Simple Transform 将平面做成一个对象,以简化主回调函数的逻辑 #include " dxstdafx.h "
// Plain vertex struct
structPlainVertex
{
FLOATx, y, z;
FLOATtu, tv;
};
// replace D3DFVF_XYZRHW with D3DFVF_XYZ
#definePLAIN_FVF (D3DFVF_XYZ | D3DFVF_TEX1)
// Object PlainVertex wrap class
classPlain
{
public :
Plain(IDirect3DDevice9 * device);
~ Plain();
HRESULTCreatePlain();
boolOnFrameMove( IDirect3DDevice9 * pd3dDevice, double fTime );
boolOnFrameRender( D3DMATERIAL9 * mtrl, IDirect3DTexture9 * tex);
public :
IDirect3DDevice9 * m_device;
IDirect3DVertexBuffer9 * m_vb;
IDirect3DIndexBuffer9 * m_ib;
};
// Constructor
Plain::Plain(IDirect3DDevice9 * device)
{
m_device = device;
m_vb = NULL;
m_ib = NULL;
}
// Create the plain first when reset device
inlineHRESULTPlain::CreatePlain()
{
HRESULThr;
PlainVertexplainVertex[] =
{
{ - 1.0f , - 1.0f , 0.0f , 1.0f , 1.0f }, // x, y, z, tu, tv : left bottom
{ 1.0f , - 1.0f , 0.0f , 0.0f , 1.0f }, // right bottom
{ 1.0f , 1.0f , 0.0f , 0.0f , 0.0f }, // right up
{ - 1.0f , 1.0f , 0.0f , 1.0f , 0.0f }, // left up
};
V_RETURN(m_device -> CreateVertexBuffer(
sizeof (plainVertex),
0 ,
PLAIN_FVF,
D3DPOOL_MANAGED,
& m_vb,
NULL));
PlainVertex * v;
V_RETURN(m_vb -> Lock( 0 , 0 , ( void ** ) & v, 0 ));
memcpy( v, plainVertex, sizeof (plainVertex) );
m_vb -> Unlock();
WORDwIndeces[] = { 3 , 2 , 0 , 2 , 1 , 0 };
V_RETURN( m_device -> CreateIndexBuffer( sizeof (wIndeces),
0 , D3DFMT_INDEX16,
D3DPOOL_MANAGED, & m_ib, NULL) );
VOID * pIndeces;
V_RETURN( m_ib -> Lock( 0 , sizeof (wIndeces), & pIndeces, 0 ) );
memcpy( pIndeces, wIndeces, sizeof (wIndeces) );
m_ib -> Unlock();
return S_OK;
}
// Things to do when frame move for this plain
inline bool Plain::OnFrameMove( IDirect3DDevice9 * pd3dDevice, double fTime )
{
D3DXMATRIX matRotY;
D3DXMatrixRotationY( & matRotY, ( float )fTime * 2.0f );
D3DXMATRIX matTrans;
D3DXMatrixTranslation( & matTrans, 0.0f , 0.0f , 0.0f );
D3DXMATRIX matResult;
matResult = matRotY * matTrans;
pd3dDevice -> SetTransform( D3DTS_WORLD, & matResult );
returntrue;
}
// Things to do when frame render for this plain
inline bool Plain::OnFrameRender(D3DMATERIAL9 * mtrl, IDirect3DTexture9 * tex)
{
if ( mtrl )
m_device -> SetMaterial(mtrl);
if ( tex )
m_device -> SetTexture( 0 , tex);
m_device -> SetSamplerState( 0 , D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
m_device -> SetSamplerState( 0 , D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
m_device -> SetSamplerState( 0 , D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
m_device -> SetStreamSource( 0 , m_vb, 0 , sizeof (PlainVertex));
m_device -> SetIndices(m_ib);
m_device -> SetFVF(PLAIN_FVF);
m_device -> DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0 , 0 , 4 , 0 , 2 );
returntrue;
}
// destructor, must invoked when lost device
Plain:: ~ Plain()
{
SAFE_RELEASE(m_vb);
SAFE_RELEASE(m_ib);
}
接下来的事情就是在主回调函数中调用上面函数了
// Declaration
Plain * g_pPlain = NULL;
// codes in OnCreateDevice
// Turn off culling
pd3dDevice -> SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
// Turn off D3D lighting
pd3dDevice -> SetRenderState( D3DRS_LIGHTING, FALSE );
// Turn on the zbuffer
pd3dDevice -> SetRenderState( D3DRS_ZENABLE, TRUE );
// Codes in OnResetDevice
g_pPlain = newPlain(pd3dDevice);
V_RETURN ( g_pPlain -> CreatePlain() );
// Codes in OnFrameMove.
// invoke plain’s OnFrameMove fisrt to set the world matrics
g_pPlain -> OnFrameMove( pd3dDevice, fTime );
// Set up our view matrix. A view matrix can be defined given an eye point,
// a point to lookat, and a direction for which way is up. Here, we set the
// eye five units back along the z-axis and up three units, look at the
// origin, and define "up" to be in the y-direction.
D3DXVECTOR3vEyePt( 0.0f , 0.0f , 4.0f );
D3DXVECTOR3vLookatPt( 0.0f , 0.0f , 0.0f );
D3DXVECTOR3vUpVec( 0.0f , 1.0f , 0.0f );
D3DXMATRIXA16 matView;
D3DXMatrixLookAtLH( & matView, & vEyePt, & vLookatPt, & vUpVec );
pd3dDevice -> SetTransform( D3DTS_VIEW, & matView );
// For the projection matrix, we set up a perspective transform (which
// transforms geometry from 3D view space to 2D viewport space, with
// a perspective divide making objects smaller in the distance). To build
// a perpsective transform, we need the field of view (1/4 pi is common),
// the aspect ratio, and the near and far clipping planes (which define at
// what distances geometry should be no longer be rendered).
D3DXMATRIXA16 matProj;
D3DXMatrixPerspectiveFovLH( & matProj, D3DX_PI / 4 , 1.0f , 1.0f , 100.0f );
pd3dDevice -> SetTransform( D3DTS_PROJECTION, & matProj );
// Codes in OnFrameRender
g_pPlain -> OnFrameRender( 0 ,g_pTexture);
// Codes in OnLostDevice
g_pPlain ->~ Plain();
从上面的代码可以看出,这个程序是将一个平面绕Y轴旋转。由于定义的定点是在[-1, 1]区间的,所以动画显示出来的效果就是绕平面中心竖线选转的。这里用到了前几章的顶点缓冲和索引缓冲,然后在平面上做了纹理贴图,利用了mipmap并 进行了双线过滤(见Plain::OnFrameRender)。需要注意的一点是D3D中默认打开了背面剔除(culling)和光照效果 (lighting),所以我们必须手动调用SetRenderState手动关闭它们(OnCreateDevice),否则动画将只现实是黑乎乎的旋 转平面正面。关闭后效果如下:
转载于:https://www.cnblogs.com/hcbin/archive/2010/05/31/1748626.html
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
