DXUT(也稱sample framework)是建立在Direct3D API之上的Direct3D應用程序框架,有了DXUT這樣一個Direct3D程序框架,只需在這個框架的基礎上編寫相應的代碼,從而簡化了windows和Direct3D
API的使用,可以高效地進行Direct3D程序設計。
生成一個Direct3D程序框架
第一步,運行Direct3D示例程序瀏覽器:

第二步,單擊"EmptyProject"中的"Installl Project"安裝工程:

第三步,在彈出的對話框中輸入新工程的名稱,修改該工程的創(chuàng)建路徑,單擊Install即可創(chuàng)建工程:

第四步,系統(tǒng)將自動完成工程的創(chuàng)建,然后彈出對話框詢問是否查看創(chuàng)建的工程文件夾中的內(nèi)容:

若選擇是,則可以查看新創(chuàng)建的工程文件夾的內(nèi)容:

使用Direct3D程序框架
通過上面的操作,Direct3D已經(jīng)為我們創(chuàng)建好了一個應用程序框架,該框架主要包括以下文件:

其中最主要的兩個文件是DXUT.h和DXUT.cpp。
除了上面這些通用文件外,Direct3D還生成了一個主程序文件,該文件的名字和工程名字相同,在此即是AppFrame.cpp。該文件主要由以下幾個回調(diào)函數(shù)構成:
bool CALLBACK IsD3D9DeviceAcceptable(D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat,
bool bWindowed, void* pUserContext);
bool CALLBACK ModifyDeviceSettings(DXUTDeviceSettings* pDeviceSettings, void* pUserContext);
HRESULT CALLBACK OnD3D9CreateDevice(IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
void* pUserContext);
HRESULT CALLBACK OnD3D9ResetDevice(IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
void* pUserContext);
void CALLBACK OnFrameMove(double fTime, float fElapsedTime, void* pUserContext);
void CALLBACK OnD3D9FrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext );
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
bool* pbNoFurtherProcessing, void* pUserContext );
void CALLBACK OnD3D9LostDevice( void* pUserContext );
void CALLBACK OnD3D9DestroyDevice( void* pUserContext );
函數(shù)名前使用"CALLBACK"表示聲明的是一個回調(diào)函數(shù),也就是說,這是DXUT框架為我們設置好的接口,DXUT框架將在合適的時機調(diào)用相應的回調(diào)函數(shù)。現(xiàn)在我們需要做的就是在這些回調(diào)函數(shù)中填寫相應的代碼完成所需要的功能。為了使DXUT框架能夠調(diào)用這些回調(diào)函數(shù),還需要在WinMain函數(shù)中為DXUT框架設置這些回調(diào)函數(shù),代碼如下:
// Set the callback functions
DXUTSetCallbackD3D9DeviceAcceptable(IsD3D9DeviceAcceptable);
DXUTSetCallbackD3D9DeviceCreated(OnD3D9CreateDevice);
DXUTSetCallbackD3D9DeviceReset(OnD3D9ResetDevice);
DXUTSetCallbackD3D9FrameRender(OnD3D9FrameRender);
DXUTSetCallbackD3D9DeviceLost(OnD3D9LostDevice);
DXUTSetCallbackD3D9DeviceDestroyed(OnD3D9DestroyDevice);
DXUTSetCallbackDeviceChanging(ModifyDeviceSettings);
DXUTSetCallbackMsgProc(MsgProc);
DXUTSetCallbackFrameMove(OnFrameMove);
DXUT框架程序的整個“生命周期”可劃分為三個階段:啟動、運行和結束。
第一階段:啟動
DXUT框架依次執(zhí)行IsD3D9DeviceAcceptable()、ModifyDeviceSettings()、OnD3D9CreateDevice()、OnD3D9ResetDevice()這4個函數(shù)。
在創(chuàng)建某個Direct3D渲染設備之前,如果需要對渲染設備的特征進行檢查,查看設備是否支持需要的功能,可將檢查代碼寫在函數(shù)IsD3D9DeviceAcceptable()中。
在某個渲染設備創(chuàng)建之前,如果需要修改該渲染設備的設置,可將代碼寫在函數(shù)ModifyDeviceSettings()中。DXUT框架接下來就根據(jù)設置(或者是默認設置)創(chuàng)建最適合當前硬件的Direct3D渲染設備。例如,當硬件不支持某些功能時,可以通過使用參考設備進行模擬,設置使用參考設備代碼通常寫在該函數(shù)中。
DXUT框架創(chuàng)建了Direct3D設備之后,接下來會調(diào)用OnD3D9CreateDevice()回調(diào)函數(shù),可在OnD3D9CreateDevice()回調(diào)函數(shù)中創(chuàng)建所有內(nèi)存池類型為D3DPOOL_MANAGED或D3DPOOL_SYSTEMMEM的資源。以類型D3DPOOL_MANAGED創(chuàng)建的設備由Direct3D系統(tǒng)代替管理(位于顯存或系統(tǒng)內(nèi)存中),以類型D3DPOOL_SYSTEMMEM創(chuàng)建的設備位于系統(tǒng)內(nèi)存中,在程序退出之前,這些資源常駐內(nèi)存,不會出現(xiàn)設備丟失的現(xiàn)象。也就是說,以這兩種內(nèi)存類型創(chuàng)建的資源不需要程序員進行管理。
DXUT框架在調(diào)用OnD3D9CreateDevice()回調(diào)函數(shù)之后,將調(diào)用OnD3D9ResetDevice()回調(diào)函數(shù)。我們可在函數(shù)OnD3D9ResetDevice()中創(chuàng)建所有內(nèi)存池類型為D3DPOOL_DEFAULT的資源,這一類資源將盡可能存放在顯存中,這樣可以提高程序的運行速度。但是,這類資源在程序運行時會出現(xiàn)設備丟失的現(xiàn)象,因此需要程序員自己管理。在設備丟失時釋放它的內(nèi)存,當設備恢復時重新為它分配內(nèi)存。此外,觀察變換矩陣和投影變換矩陣以及在整個程序運行期間保持不變的渲染狀態(tài)通常也在該回調(diào)函數(shù)中設置。
如果性能不是很重要,使用D3DPOOL_MANAGED內(nèi)存類型資源永遠是一種安全的選擇。
第二階段:運行
DXUT框架調(diào)用回調(diào)函數(shù)MsgProc()處理各類消息,并在空閑時間反復調(diào)用OnFrameMove()和OnFrameRender()兩個函數(shù)進行場景渲染。
在每一幀中,程序為實現(xiàn)對場景的刷新,為用戶輸入的響應而編寫的代碼通常寫在函數(shù)OnFrameMove()中,例如設置世界變換矩陣實現(xiàn)物體的運動,它相當于“update”的性質(zhì),真正進行渲染的代碼寫在函數(shù)OnFrameRender()中。
需要說明的是,在應用程序運行期間,當Direct3D設備變?yōu)閬G失狀態(tài)時,DXUT框架會調(diào)用OnD3D9LostDevice()函數(shù),釋放所有在回調(diào)函數(shù)OnD3D9ResetDevice()中創(chuàng)建的設備資源。也就是說,這時釋放的資源都是D3DPOOL_DEFAULT類型的。當Direct3D設備從丟失狀態(tài)恢復時,DXUT框架會調(diào)用回調(diào)函數(shù)OnD3D9ResetDevice()重新創(chuàng)建所有類型為D3DPOOL_DEFAULT的資源。也就是說,在程序運行時,如果出現(xiàn)設備丟失現(xiàn)象,OnD3D9LostDevice()和OnD3D9ResetDevice()這一對函數(shù)就需要分別調(diào)用一次。
第三階段:退出
在退出程序時,DXUT框架會依次調(diào)用OnD3D9LostDevice()和OnD3D9DestroyDevice()回調(diào)函數(shù),在函數(shù)OnD3D9LostDevice()中釋放由函數(shù)OnD3D9ResetDevice()創(chuàng)建的資源,在函數(shù)OnD3D9DestroyDevice()中釋放由函數(shù)OnD3D9CreateDevice()創(chuàng)建的資源。
AppFrame.cpp的全部代碼如下:
#include "DXUT.h"
#include "resource.h"
//--------------------------------------------------------------------------------------
// Rejects any D3D9 devices that aren't acceptable to the app by returning false.
//--------------------------------------------------------------------------------------
bool CALLBACK IsD3D9DeviceAcceptable(D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat,
bool bWindowed, void* pUserContext)
{
// Typically want to skip back buffer formats that don't support alpha blending
IDirect3D9* pD3D = DXUTGetD3D9Object();
/*
HRESULT CheckDeviceFormat(
UINT Adapter,
D3DDEVTYPE DeviceType,
D3DFORMAT AdapterFormat,
DWORD Usage,
D3DRESOURCETYPE RType,
D3DFORMAT CheckFormat
);
/*/
if(FAILED(pD3D->CheckDeviceFormat(pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat,
D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, BackBufferFormat)))
{
return false;
}
return true;
}
//--------------------------------------------------------------------------------------
// Before a device is created, modify the device settings as needed.
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings(DXUTDeviceSettings* pDeviceSettings, void* pUserContext)
{
return true;
}
//--------------------------------------------------------------------------------------
// Create any D3D9 resources that will live through a device reset (D3DPOOL_MANAGED)
// and aren't tied to the back buffer size.
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D9CreateDevice(IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
void* pUserContext)
{
return S_OK;
}
//--------------------------------------------------------------------------------------
// Create any D3D9 resources that won't live through a device reset (D3DPOOL_DEFAULT)
// or that are tied to the back buffer size.
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D9ResetDevice(IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
void* pUserContext)
{
return S_OK;
}
//--------------------------------------------------------------------------------------
// Handle updates to the scene. This is called regardless of which D3D API is used.
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove(double fTime, float fElapsedTime, void* pUserContext)
{
}
//--------------------------------------------------------------------------------------
// Render the scene using the D3D9 device
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9FrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
HRESULT hr;
// Clear the render target and the zbuffer
V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 5, 5, 5), 1.0f, 0) );
// Render the scene
if( SUCCEEDED( pd3dDevice->BeginScene() ) )
{
V( pd3dDevice->EndScene() );
}
}
//--------------------------------------------------------------------------------------
// Handle messages to the application
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
bool* pbNoFurtherProcessing, void* pUserContext )
{
return 0;
}
//--------------------------------------------------------------------------------------
// Release D3D9 resources created in the OnD3D9ResetDevice callback
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9LostDevice( void* pUserContext )
{
}
//--------------------------------------------------------------------------------------
// Release D3D9 resources created in the OnD3D9CreateDevice callback
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9DestroyDevice( void* pUserContext )
{
}
//--------------------------------------------------------------------------------------
// Initialize everything and go into a render loop
//--------------------------------------------------------------------------------------
INT WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR, int )
{
// Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
// Set the callback functions
DXUTSetCallbackD3D9DeviceAcceptable(IsD3D9DeviceAcceptable);
DXUTSetCallbackD3D9DeviceCreated(OnD3D9CreateDevice);
DXUTSetCallbackD3D9DeviceReset(OnD3D9ResetDevice);
DXUTSetCallbackD3D9FrameRender(OnD3D9FrameRender);
DXUTSetCallbackD3D9DeviceLost(OnD3D9LostDevice);
DXUTSetCallbackD3D9DeviceDestroyed(OnD3D9DestroyDevice);
DXUTSetCallbackDeviceChanging(ModifyDeviceSettings);
DXUTSetCallbackMsgProc(MsgProc);
DXUTSetCallbackFrameMove(OnFrameMove);
// TODO: Perform any application-level initialization here
// Initialize DXUT and create the desired Win32 window and Direct3D device for the application
DXUTInit( true, true ); // Parse the command line and show msgboxes
DXUTSetHotkeyHandling( true, true, true ); // handle the default hotkeys
DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
DXUTCreateWindow( L"AppFrame Sample" );
DXUTCreateDevice( true, 640, 480 );
// Start the render loop
DXUTMainLoop();
// TODO: Perform any application-level cleanup here
return DXUTGetExitCode();
}
運行效果圖:

下載示例工程