Direct3D的初始化步骤如下:
1、 创建D3D对象,即通过Direct3DCreate9(D3D_SDK_VERSION)函数创建IDirect3D9对象;该对象用于设备枚举:获取系统中可用的每块图形卡的性能、显示模式、格式等信息。
2、 通过D3D对象创建D3D设备对象,即调用IDirect3D9的成员函数CreateDevice来创建。(在此之前要初始化一些参数)
3、 最后就可以根据D3D设备对象来进行绘制我们想要的场景了
4、 程序结束应该释放这两个对象,先释放设备对象,然后释放D3D对象,因为设备对象由D3D对象创建。
说明:先创建D3D对象,然后通过D3D对象创建D3D设备对象的好处是,D3D对象可以进行设备枚举,如检测设备的性能,使创建的D3D设备对象在执行图形渲染时能够充分利用硬件的处理功能。
初始化代码如下:
#include <windows.h>
#include <tchar.h>
#include <d3dx9.h>
#pragma comment(lib,"D3D9.lib")
//函数声明
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);//窗口过程
bool InitD3D(HINSTANCE hInstance);
void Cleanup();
void Render(); //绘制
//窗口相关全局变量
const TCHAR g_szWindowTitleName[] = _T("InitDirect3D"); //窗口标题
const TCHAR g_szWindowClassName[] = _T("WindowClass"); //窗口类名
int g_cxWindow = 600; //窗口宽
int g_cyWindow = 480; //窗口高
//Direct3D全局变量
IDirect3D9 * g_pD3d = nullptr; //Direct3D对象指针
IDirect3DDevice9 * g_pDevice = nullptr; //Direct3D设备对象指针
int WINAPI _tWinMain(HINSTANCE hInstance,
HINSTANCE hPreInstance,
LPTSTR lpCmdLine,
int nShowCmd)
{
if (!InitD3D(hInstance))
{
MessageBox(NULL, _T("初始化D3D失败"), NULL, MB_OK);
return 0;
}
MSG msg;
memset(&msg, 0, sizeof(msg));
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Render(); //5 绘制
}
}
Cleanup(); //6 清理资源
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
DestroyWindow(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
bool InitD3D(HINSTANCE hInstance)
{
WNDCLASS wndClass; //初始化窗口类结构体
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.hInstance = hInstance;
wndClass.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.lpfnWndProc = WndProc;
wndClass.lpszClassName = g_szWindowClassName;
wndClass.lpszMenuName = NULL;
BOOL bRet;
bRet = RegisterClass(&wndClass); //注册窗口类
if (!bRet)
{
MessageBox(NULL, _T("Register window class fail"), NULL, MB_OK);
return FALSE;
}
HWND hWnd;
hWnd = CreateWindow(g_szWindowClassName,//创建窗口
g_szWindowTitleName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
g_cxWindow,
g_cyWindow,
NULL,
NULL,
hInstance,
NULL);
if (!hWnd)
{
MessageBox(NULL, _T("Create Window FAil"), NULL, MB_OK);
return FALSE;
}
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
//init Direct3D
g_pD3d = Direct3DCreate9(D3D_SDK_VERSION); //1、创建D3D对象
if (!g_pD3d)
{
MessageBox(NULL, _T("创建D3D对象失败!"), NULL, MB_OK);
return false;
}
D3DCAPS9 caps; //2、检查设备能力,硬件是否支持顶点运算
g_pD3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
int cap;
if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
cap = D3DCREATE_HARDWARE_VERTEXPROCESSING; //用硬件方式处理顶点运算
else
cap = D3DCREATE_SOFTWARE_VERTEXPROCESSING; //用软件方式处理顶点运算
D3DPRESENT_PARAMETERS d3dpp; //3、初始化D3DPRESENT_PARAMETERS结构体
memset(&d3dpp, 0, sizeof(D3DPRESENT_PARAMETERS));
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.Windowed = true;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
HRESULT hr;
hr = g_pD3d->CreateDevice(D3DADAPTER_DEFAULT, //4、创建D3D设备对象
D3DDEVTYPE_HAL,
hWnd,
cap,
&d3dpp,
&g_pDevice);
if (FAILED(hr))
{
MessageBox(NULL, _T("创建D3D设备对象失败!"), NULL, MB_OK);
return false;
}
return true;
}
void Cleanup()
{
if (g_pDevice){ g_pDevice->Release(); g_pDevice = nullptr; }
if (g_pD3d){ g_pD3d->Release(); g_pD3d = nullptr; }
}
void Render()
{
g_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 200, 0), 1.f, 0);
HRESULT hr;
hr = g_pDevice->BeginScene();
if (SUCCEEDED(hr))
{
//......render
g_pDevice->EndScene();
}
g_pDevice->Present(nullptr, nullptr, NULL, nullptr);
}
运行效果如下:
下面对以上用的函数及其结构体类型进行说明:
1、IDirect3D9::GetDeviceCaps
该函数的功能是获取设备的相关信息
函数原型如下:
HRESULT GetDeviceCaps(
[in] UINT Adapter,
[in] D3DDEVTYPE DeviceType,
[out] D3DCAPS9 *pCaps
);
参数说明:
Aapter:显卡的序号,一般为D3DADAPTER_DEFAULT表示用主显卡适配器
DeviceType:D3DDEVTYPE枚举类型,决定显卡的类型,通常用D3DDEVTYPE_HAL或D3DDEVTPYE_REF
pCaps:D3DCAPS9类型的指针,接受设备相关的信息
2、struct D3DCAPS9
代表了硬件设备的公开能力,通常用其成员DevCaps与D3DDEVCAPS_HWTRANSFORMANDLIGHT进行按位与操作来判断硬件是否支持变换和光照
3、struct D3DPRESENT_PARAMETERS
创建D3D设备对象时需要使用的结构体参数,原型及其说明如下:
typedef struct D3DPRESENT_PARAMETERS {
UINT BackBufferWidth; //后台缓存的宽度和高度,如果为窗口模式且该变量设置为0时,则系统自动使用窗口客户区域的宽度和高度作为后台缓存的宽度和高度(如果hDeviceWindow为NULL,则为焦点窗口);
UINT BackBufferHeight; //如果为全屏模式,则必须为枚举显示模式找到的宽度和高度
D3DFORMAT BackBufferFormat; //后台缓存的格式,该值必须是渲染目标格式之一(可以通过CheckDeviceType来获得,也可以用GetDisplayMode来获取当前格式);在窗口模式下,如果将值设置为D3DFMT_UNKNOWN,则系统用当前的显示模式的格式,从而可以避免调用GetDisplayMode
UINT BackBufferCount; //后台缓存的格式,其值的范围在0到D3DPRESENT_BACK_BUFFERS_MAX之间,0被处理为1,如果不能创建指定数量的后台缓存,那么系统会自动填充能被创建的后台缓存个数
D3DMULTISAMPLE_TYPE MultiSampleType; //多重采样的类型,用于反锯齿。该值必须设置为D3DMULTISAMPLE_NONE,除非SwapEffect被设置为D3DSWAPEFFECT_DISCARD
DWORD MultiSampleQuality; //采样的质量水平,该值的有效范围为0到CheckDeviceMultiSampleType函数返回值之间。值太大则会失败
D3DSWAPEFFECT SwapEffect; //指定后台缓存如何赋值到前台缓存,在窗口模式下,如果设置为D3DSWAPEFFECT_FLIP,则会创建一个额外的后台缓存,在提交的时候用来拷贝将成为前台缓存的缓存。通常设置为D3DSWAPEFFECT_DISCARD
HWND hDeviceWindow; //设备窗口句柄,决定了后台缓存在屏幕的位置和大小。对于全屏模式,这是一个顶层窗口的句柄;对于窗口模式,这个句柄将标识了默认目标窗口,如果为NULL,则用焦点窗口(焦点窗口即为在创建D3D设备对象时,对函数IDirect3D9::CreateDevice指定的第三个参数)
BOOL Windowed; //决定是否为窗口模式
BOOL EnableAutoDepthStencil; //决定是否让Direct3D深度缓存,当设备创建时,自动创建深度模版缓存
D3DFORMAT AutoDepthStencilFormat; //深度模版缓存的格式,这个格式必须有效
DWORD Flags; //附加特性,通常设置为0
UINT FullScreen_RefreshRateInHz; //全屏模式下显示适配器刷新屏幕的频率,通常指定为:D3DPRESENT_RATE_DEFAULT;对于窗口模式必须指定为0
UINT PresentationInterval; //指定交换链的后台缓存提交到前台缓存的最大频率,通常设置为D3DPRESENT_INTERVAL_IMMEDIATE(立即提交)、D3DPRESENT_INTERVAL_DEFAULT(由Direct3D选择提交频率,同长等于刷新频率)
} D3DPRESENT_PARAMETERS, *LPD3DPRESENT_PARAMETERS;
4、IDirect3D9::CreateDevice
创建一个D3D设备对象,函数原型如下:
HRESULT CreateDevice(
[in] UINT Adapter,
[in] D3DDEVTYPE DeviceType,
[in] HWND hFocusWindow,
[in] DWORD BehaviorFlags,
[in, out] D3DPRESENT_PARAMETERS *pPresentationParameters,
[out, retval] IDirect3DDevice9 **ppReturnedDeviceInterface
);
Adapter:显卡号,一般用D3DADAPTER_DEFAULT
DeviceType:设备类型
hFocusWindow:焦点窗口,在全屏模式下必须指定问顶层窗口;在窗口模式下,该值可以为NULL,如果D3DPRESENT_PARAMETERS的窗口句柄成员设置为非空值的话。
BehaviorFlags:组合一个或多个值来空置设备的创建行为,如:D3DCREATE_HARDWARE_VERTEXPROCESSING、D3DCREATE_SOFTWARE_VERTEXPROCESSING 顶点的处理方式。
pPresentationParameters:D3DPRESENT_PARAMETERS结构体变量
ppReturnedDeviceInterface:返回D3D设备对象的指针
5、IDirect3DDevice9::Clear
可以清除视口的颜色缓存、深度缓存、和模版缓存
HRESULT Clear(
[in] DWORD Count,
[in] const D3DRECT *pRects,
[in] DWORD Flags,
[in] D3DCOLOR Color,
[in] float Z,
[in] DWORD Stencil
);
Count:矩形数组中矩形的个数,可以为0
pRects:矩形数组的指针
Flags:可以组合一个或多个标记D3DCLEAR_STENCIL、D3DCLEAR_TARGET、D3DCLEAR_ZBUFFER
Color:渲染目标被清除的目标颜色
Z:清除深度缓存到指定的值,范围为0-1
Stencil:清除模版缓存为指定的值
注意:如果清除渲染目标的模版缓存或深度缓存,而没有关联深度缓存的话,该函数将调用失败;当清楚模版缓存,而深度缓存没有包含模版数据时,函数调用也会失败!
6、IDirect3DDevice9::BeginScene
开始绘制
7、IDirect3DDevice9::EndScene
结束绘制
8、IDirect3DDevice9::Present
在后台缓存中绘制完图形后,调用该函数将在后台缓存中绘制的内容提交到前台显示,这样绘制的图形就显示在屏幕上了。
HRESULT Present(
[in] const RECT *pSourceRect,
[in] const RECT *pDestRect,
[in] HWND hDestWindowOverride,
[in] const RGNDATA *pDirtyRegion
);
pSourceRect:该值必须设置为NULL,除非对D3DPRESENT_PARAMETERS结构体变量的成员SwapEffect设置其值为D3DSWAPEFFECT_COPY;该参数表示被提交的源矩形区域,如果为NULL,表示整个源表面,如果矩形区域超过了源表面的大小,那么矩形将被裁剪到源表面大小
pDestRect:该值必须设置为NULL,除非对D3DPRESENT_PARAMETERS结构体变量的成员SwapEffect设置其值为D3DSWAPEFFECT_COPY;该参数表示目标矩形区域,如果为NULL,则表示整个客户区,如果矩形区域超过了客户区的大小,那么矩形将被裁剪到客户区域的大小
hDestWindowOverride:目标矩形区域的窗口句柄,如果为NULL,则用D3DPRESENT_PARAMETERS中的窗口句柄成员
pDirtyRegion:该值必须为NULL,除非对D3DPRESENT_PARAMETERS结构体变量的成员SwapEffect设置其值为D3DSWAPEFFECT_COPY;该参数主要用于优化提交,包含了多个矩形,以表示一个区域。通常设置为NULL