一、坐标空间
1.1 局部坐标系
用于描述物体自身属性的独立坐标系,它相对于物体中心位置构成一个模型空间。在该模型空间,描述了物体的方向和构成物体的元素相对于物体中心的位置。
1.2 世界坐标系
用于建立一个描述其他坐标系所需要的参考框架,以便指定物体在该坐标系中的位置、方向及大小。其描述的空间称为世界空间,包含了所有的物体模型,并且这些物体模型被组合到一起而形成一个场景。
1.3 观察坐标系
用于指定观察三维空间中的物体的方向和位置,其原点指定了摄像机的位置。它定义了摄像机的屏幕可视区域,可产生观察物体“近大远小”的效果。
二、数学对象
2.1 向量
D3DXVECTOR3是Direct3D中的向量,当然也有D3DXVECTOR2和D3DXVECTOR4两种形式,并且重载了加减乘除、赋值等操作与求模、规格化、点积、叉积等运算。
2.2 矩阵
D3DMATRIX是Direct3D中的矩阵,表示4*4的矩阵,其许多操作可参见SDK帮助。
三、几何变换
3.1 世界变换
包括平移、旋转、缩放变换,相关函数有D3DXMatrixTranslation、D3DXMatrixRotation、D3DXMatrixSaling等,应用到设备采用SetTransform(D3DTS_WORLD, &matWorld)。
3.2 观察变换
指定虚拟摄像机的位置、观察点位置及正方向,相关函数有D3DXMatrixLookAtLH等,应用到设备采用SetTransform(D3DTS_VIEW,&matView)。
3.3 投影变换
将位于视截体内的物体模型映射到投影窗口中,相关函数有D3DXMatrixPerspectiFovLH等,应用到设备采用SetTransform(D3DTS_PROJECTION,&matProj)。
3.4 视口变换
将投影窗口中的图像转换到显示屏幕的程序窗口中,视口由D3DVIEWPORT9描述,通过调用SetViewport函数就可以自动完成视口变换。
四、程序实例
下面创建的程序实现一个立方体分别绕X、Y和Z轴旋转的效果。
#include <d3d9.h>
#include <d3dx9.h>
//Make sure the libraries d3d9.lib and d3dx9.lib are linked
//Add this source to your project
//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
LPDIRECT3D9 g_pD3D = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Our rendering device
LPDIRECT3DVERTEXBUFFER9 g_pVertexBuf = NULL;
LPDIRECT3DINDEXBUFFER9 g_pIndexBuf = NULL;
struct CUSTOMVERTEX
{
FLOAT _x,_y,_z;
DWORD _color;
CUSTOMVERTEX(FLOAT x, FLOAT y, FLOAT z, DWORD color)
:_x(x),_y(y),_z(z),_color(color){}
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
//-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: Initializes Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
// Create the D3D object, which is needed to create the D3DDevice.
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
// Set up the structure used to create the D3DDevice. Most parameters are
// zeroed out. We set Windowed to TRUE, since we want to do D3D in a
// window, and then set the SwapEffect to "discard", which is the most
// efficient method of presenting the back buffer to the display. And
// we request a back buffer format that matches the current desktop display
// format.
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
// Create the Direct3D device. Here we are using the default adapter (most
// systems only have one, unless they have multiple graphics hardware cards
// installed) and requesting the HAL (which is saying we want the hardware
// device rather than a software one). Software vertex processing is
// specified since we know it will work on all cards. On cards that support
// hardware vertex processing, though, we would see a big performance gain
// by specifying hardware vertex processing.
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
return E_FAIL;
}
// 创建顶点缓存,填充顶点数据
g_pd3dDevice->CreateVertexBuffer(8*sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &g_pVertexBuf, NULL);
CUSTOMVERTEX *pVertices = NULL;
g_pVertexBuf->Lock(0, 0,(void**)&pVertices, 0);
pVertices[0] = CUSTOMVERTEX(-5.0F, 5.0F, -5.0F, D3DCOLOR_XRGB(255, 0, 0));
pVertices[1] = CUSTOMVERTEX(-5.0F, 5.0F, 5.0F, D3DCOLOR_XRGB( 0,255, 0));
pVertices[2] = CUSTOMVERTEX( 5.0F, 5.0F, 5.0F, D3DCOLOR_XRGB( 0, 0,255));
pVertices[3] = CUSTOMVERTEX( 5.0F, 5.0F, -5.0F, D3DCOLOR_XRGB(255,255, 0));
pVertices[4] = CUSTOMVERTEX(-5.0F, -5.0F, -5.0F, D3DCOLOR_XRGB( 0, 0,255));
pVertices[5] = CUSTOMVERTEX(-5.0F, -5.0F, 5.0F, D3DCOLOR_XRGB(255,255, 0));
pVertices[6] = CUSTOMVERTEX( 5.0F, -5.0F, 5.0F, D3DCOLOR_XRGB(255, 0, 0));
pVertices[7] = CUSTOMVERTEX( 5.0F, -5.0F, -5.0F, D3DCOLOR_XRGB( 0,255, 0));
g_pVertexBuf->Unlock();
// 创建索引缓存,填充索引数据
g_pd3dDevice->CreateIndexBuffer(36*sizeof(WORD), 0, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &g_pIndexBuf, NULL);
WORD *pIndices = NULL;
g_pIndexBuf->Lock(0, 0, (void**)&pIndices, 0);
pIndices[0] = 0; pIndices[1] = 1; pIndices[2] = 2;
pIndices[3] = 0; pIndices[4] = 2; pIndices[5] = 3;
pIndices[6] = 0; pIndices[7] = 3; pIndices[8] = 7;
pIndices[9] = 0; pIndices[10] = 7; pIndices[11] = 4;
pIndices[12] = 0; pIndices[13] = 4; pIndices[14] = 5;
pIndices[15] = 0; pIndices[16] = 5; pIndices[17] = 1;
pIndices[18] = 2; pIndices[19] = 6; pIndices[20] = 7;
pIndices[21] = 2; pIndices[22] = 7; pIndices[23] = 3;
pIndices[24] = 2; pIndices[25] = 5; pIndices[26] = 6;
pIndices[27] = 2; pIndices[28] = 1; pIndices[29] = 5;
pIndices[30] = 4; pIndices[31] = 6; pIndices[32] = 5;
pIndices[33] = 4; pIndices[34] = 7; pIndices[35] = 6;
g_pIndexBuf->Unlock();
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------
VOID Cleanup()
{
if( g_pd3dDevice != NULL)
g_pd3dDevice->Release();
if( g_pD3D != NULL)
g_pD3D->Release();
}
//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
//-----------------------------------------------------------------------------
VOID Render()
{
if( NULL == g_pd3dDevice )
return;
// Clear the backbuffer to a blue color
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
// Begin the scene
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
// 世界变换
D3DXMATRIX matWorld, Rx, Ry, Rz;
D3DXMatrixIdentity(&matWorld);
D3DXMatrixRotationX(&Rx, ::timeGetTime()/1000.0f);
D3DXMatrixRotationY(&Ry, ::timeGetTime()/1000.0f);
D3DXMatrixRotationZ(&Rz, ::timeGetTime()/1000.0f);
matWorld = Rx * Ry * Rz * matWorld;
g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);
// 观察变换
D3DXMATRIX matView;
D3DXVECTOR3 vEye(0.0f, 0.0f, -30.0f);
D3DXVECTOR3 vAt(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 vUp(0.0f, 1.0f, 0.0f);
D3DXMatrixLookAtLH(&matView, &vEye, &vAt, &vUp);
g_pd3dDevice->SetTransform(D3DTS_VIEW,&matView);
// 投影变换
D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4.0f, 1.0f, 1.0f, 1000.0f);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION,&matProj);
// 视口变换
D3DVIEWPORT9 vp = {0, 0, 300, 250, 0, 1};
g_pd3dDevice->SetViewport(&vp);
// 设置渲染状态
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
g_pd3dDevice->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
// 渲染三角形
g_pd3dDevice->SetStreamSource(0, g_pVertexBuf, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
g_pd3dDevice->SetIndices(g_pIndexBuf);
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);
// End the scene
g_pd3dDevice->EndScene();
}
// Present the backbuffer contents to the display
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY:
Cleanup();
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
// Register the window class
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
L"D3D Tutorial", NULL };
RegisterClassEx( &wc );
// Create the application's window
HWND hWnd = CreateWindow( L"D3D Tutorial", L"D3D Tutorial 01: CreateDevice",
WS_OVERLAPPEDWINDOW, 100, 100, 640, 480,
GetDesktopWindow(), NULL, wc.hInstance, NULL );
// Initialize Direct3D
if( SUCCEEDED( InitD3D( hWnd ) ) )
{
// Show the window
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
MSG mssg;
PeekMessage( &mssg, NULL, 0, 0, PM_NOREMOVE);
// run till completed
while (mssg.message!=WM_QUIT)
{
// is there a message to process?
if (PeekMessage( &mssg, NULL, 0, 0, PM_REMOVE))
{
// dispatch the message
TranslateMessage(&mssg);
DispatchMessage(&mssg);
}
else
{
//No message to process?
// Then do your game stuff here
Render();
}
}
}
UnregisterClass( L"D3D Tutorial", wc.hInstance );
return 0;
}
本文为个人读书笔记,主要着重于编程学习,参考文献包括:
[1] 郑阿奇. DirectX 3D游戏编程实用教程[M]. 北京:电子工业出版社, 2011.
[2] Introduction to 3D Game Programming with DirectX 9.