Direct3D對象
Microsoft Direct3D的一種實現方式是通過組件對象模型(Component Object
Model, COM)及其接口實現的,在用C++語言和COM接口方式開發的程序中可以直接訪問這些接口和對象。Direct3D對象是Direct3D程序中需要創建的第一個對象,也是需要最后一個釋放的對象,這里所說的對象是指COM對象。通過Direct3D對象,可以枚舉和檢索Direct3D設備,這樣應用程序就可以在不需要創建設備對象的前提下選擇Direct3D渲染設備。
在用C++語言編寫Direct3D程序時,需要先獲取一個指向IDirect3D9接口的指針,從而可以通過該接口調用Direct3D對象的功能。
創建Direct3D設備對象
創建Direct3D設備對象時,需要先創建Direct3D對象,然后再調用Direct3D對象的接口函數IDirect3D9::CreateDevice創建Direct3D設備對象。通過同一個Direct3D對象創建的所有Direct3D設備對象共享相同的物理資源(顯卡)。因為共享同一硬件,所以如果通過一個Direct3D對象創建多個Direct3D渲染設備對象會明顯降低系統性能。
在創建Direct3D設備對象之前,還需要先初始化D3DPRESENT_PARAMETERS結構,該結構用于創建Direct3D設備對象。D3DPRESENT_PARAMETERS結構定義了Direct3D設備對象的相關信息,而這些信息將會影響Direct3D設備的顯示方法。該結構的定義如下:
Describes the presentation parameters.
typedef struct D3DPRESENT_PARAMETERS {
UINT BackBufferWidth, BackBufferHeight;
D3DFORMAT BackBufferFormat;
UINT BackBufferCount;
D3DMULTISAMPLE_TYPE MultiSampleType;
DWORD MultiSampleQuality;
D3DSWAPEFFECT SwapEffect;
HWND hDeviceWindow;
BOOL Windowed;
BOOL EnableAutoDepthStencil;
D3DFORMAT AutoDepthStencilFormat;
DWORD Flags;
UINT FullScreen_RefreshRateInHz;
UINT PresentationInterval;
} D3DPRESENT_PARAMETERS, *LPD3DPRESENT_PARAMETERS;
Members
- BackBufferWidth, BackBufferHeight
- Width and height of the new swap chain's back
buffers, in pixels. If Windowed is FALSE (the presentation is full-screen),
these values must equal the width and height of one of the enumerated
display modes found through IDirect3D9::EnumAdapterModes. If Windowed is
TRUE and either of these values is zero, the corresponding dimension of the
client area of the hDeviceWindow (or the focus window, if hDeviceWindow is
NULL) is taken.
- BackBufferFormat
- The back buffer format. For more information about
formats, see D3DFORMAT. This value must be one of the render-target formats
as validated by IDirect3D9::CheckDeviceType. You can use
IDirect3DDevice9::GetDisplayMode to obtain the current format.
In fact, D3DFMT_UNKNOWN can be specified for the
BackBufferFormat while in windowed mode. This tells the runtime to use the
current display-mode format and eliminates the need to call
IDirect3DDevice9::GetDisplayMode.
For windowed applications, the back buffer format
no longer needs to match the display-mode format because color conversion
can now be done by the hardware (if the hardware supports color conversion).
The set of possible back buffer formats is constrained, but the runtime will
allow any valid back buffer format to be presented to any desktop format.
(There is the additional requirement that the device be operable in the
desktop mode; devices typically do not operate in 8 bits per pixel modes.)
Full-screen applications cannot do color
conversion.
- BackBufferCount
- This value can be between 0 and
D3DPRESENT_BACK_BUFFERS_MAX (or D3DPRESENT_BACK_BUFFERS_MAX_EX when using
Direct3D 9Ex). Values of 0 are treated as 1. If the number of back buffers
cannot be created, the runtime will fail the method call and fill this value
with the number of back buffers that could be created. As a result, an
application can call the method twice with the same D3DPRESENT_PARAMETERS
structure and expect it to work the second time.
The method fails if one back buffer cannot be
created. The value of BackBufferCount influences what set of swap effects
are allowed. Specifically, any D3DSWAPEFFECT_COPY swap effect requires that
there be exactly one back buffer.
- MultiSampleType
- Member of the D3DMULTISAMPLE_TYPE enumerated type.
The value must be D3DMULTISAMPLE_NONE unless SwapEffect has been set to
D3DSWAPEFFECT_DISCARD. Multisampling is supported only if the swap effect is
D3DSWAPEFFECT_DISCARD.
- MultiSampleQuality
- Quality level. The valid range is between zero and
one less than the level returned by pQualityLevels used by
IDirect3D9::CheckDeviceMultiSampleType. Passing a larger value returns the
error D3DERR_INVALIDCALL. Paired values of render targets or of depth
stencil surfaces and D3DMULTISAMPLE_TYPE must match.
- SwapEffect
- Member of the D3DSWAPEFFECT enumerated type. The
runtime will guarantee the implied semantics concerning buffer swap
behavior; therefore, if Windowed is TRUE and SwapEffect is set to
D3DSWAPEFFECT_FLIP, the runtime will create one extra back buffer and copy
whichever becomes the front buffer at presentation time.
D3DSWAPEFFECT_COPY requires that BackBufferCount be
set to 1.
D3DSWAPEFFECT_DISCARD will be enforced in the debug
runtime by filling any buffer with noise after it is presented.
- hDeviceWindow
- The device window determines the location and size
of the back buffer on screen. This is used by Direct3D when the back buffer
contents are copied to the front buffer during IDirect3DDevice9::Present.
Note that no attempt is made by the runtime to
reflect user changes in window size. The back buffer is not implicitly reset
when this window is reset. However, the IDirect3DDevice9::Present
method does automatically track window position changes.
- Windowed
- TRUE if the application runs windowed; FALSE if
the application runs full-screen.
- EnableAutoDepthStencil
- If this value is TRUE, Direct3D will manage depth
buffers for the application. The device will create a depth-stencil buffer
when it is created. The depth-stencil buffer will be automatically set as
the render target of the device. When the device is reset, the depth-stencil
buffer will be automatically destroyed and recreated in the new size.
If EnableAutoDepthStencil is TRUE, then
AutoDepthStencilFormat must be a valid depth-stencil format.
- AutoDepthStencilFormat
- Member of the D3DFORMAT enumerated type.
The format of the automatic depth-stencil surface that the device will
create. This member is ignored unless EnableAutoDepthStencil is TRUE.
- Flags
- One of the D3DPRESENTFLAG constants.
- FullScreen_RefreshRateInHz
- The rate at which the display adapter refreshes
the screen. The value depends on the mode in which the application is
running:
- For windowed mode, the refresh rate must be 0.
- For full-screen mode, the refresh rate is one
of the refresh rates returned by IDirect3D9::EnumAdapterModes.
- PresentationInterval
- The maximum rate at which the swap chain's back
buffers can be presented to the front buffer. For a detailed explanation of
the modes and the intervals that are supported, see D3DPRESENT.
Direct3D程序基本結構
雖然Direct3D功能非常強大,但是Direct3D程序的基本結構非常簡單清晰,它主要有5個步驟:
(1)創建一個Windows窗口。
(2)初始化Direct3D,包括創建Direct3D對象、Direct3D設備對象以及要渲染的圖形對象。
(3)消息循環。
(4)渲染圖形。
(5)清除在初始化時創建的所有COM對象,退出程序。
其中消息循環和渲染圖形不斷進行,如果程序有消息需要處理,則先處理消息,然后再渲染圖形;如果沒有消息處理,則一直不停地渲染圖形,直到退出Direct3D程序。
最簡單的Direct3D程序
#include <d3d9.h>
#define CLASS_NAME "GameApp"
#define release_com(p) { if(p) { (p)->Release(); (p) = NULL; } }
IDirect3D9* g_d3d;
IDirect3DDevice9* g_device;
bool init_d3d(HWND hwnd)
{
g_d3d = Direct3DCreate9(D3D_SDK_VERSION);
if(g_d3d == NULL)
return false;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
if(FAILED(g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_device)))
{
return false;
}
return true;
}
void cleanup()
{
release_com(g_device);
release_com(g_d3d);
}
void render()
{
g_device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(45, 50, 170), 1.0f, 0);
g_device->BeginScene();
// render game scene here
g_device->EndScene();
g_device->Present(NULL, NULL, NULL, NULL);
}
LRESULT WINAPI WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_KEYDOWN:
if(wParam == VK_ESCAPE)
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR, INT)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_CLASSDC;
wc.lpfnWndProc = WinProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = inst;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = CLASS_NAME;
wc.hIconSm = NULL;
if(! RegisterClassEx(&wc))
return -1;
HWND hwnd = CreateWindow(CLASS_NAME, "Direct3D App", WS_OVERLAPPEDWINDOW, 200, 100, 600, 500,
NULL, NULL, wc.hInstance, NULL);
if(hwnd == NULL)
return -1;
if(init_d3d(hwnd))
{
ShowWindow(hwnd, SW_SHOWDEFAULT);
UpdateWindow(hwnd);
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
render();
}
}
}
cleanup();
UnregisterClass(CLASS_NAME, wc.hInstance);
return 0;
}
運行截圖:
