一、Direct3D概述
DirectX是微软公司开发的一套功能丰富的底层API,其功能涵盖了:
2D/3D图形加速的支持、
各种输入设备的控制、
声音和音乐输出的混音和采样、
多玩家网络游戏的控制、
各种多媒体流媒体模式的控制等。
DirectX在体系结构上很突出的优点是它使用了两层驱动——HAL和REF,那些为硬件所支持的特定功能可由HAL来控制(即可以充分地发挥硬件的加速功能),从而可以获得理想的运行速度。而对于那些不为硬件所支持的功能,借助REF,程序能够以软件方式来模拟相应的运算或处理过程,从而使得无论硬件配置是否高端,开发人员都可以完整地体验和测试DirectX所提供的全部功能。
Direct3D是DirectX的三维部分,它是一套底层图形API,借助该API,我们能够利用硬件加速功能来绘制3D场景。Direct3D可以被视作应用程序与图形设备(3D硬件)交互的中介。它们之间的关系如下:
在Direct3D和图形设备之间有一个中间环节——HAL(Hardware Abstraction Layer,硬件抽象层)。由于市面上的图形卡品种繁多,每种卡的性能和实现同样功能的机理都有差异,所以Direct3D无法与图形设备直接交互。所以,Direct3D就需要设备制造商实现一个HAL。HAL是一个指示设备完成某些操作的设备相关的代码集。
有时,Direct3D提供的某些功能不为所使用的图形设备支持,但是仍然希望使用这些功能。为了满足这种需求,Direct3D提供了参考光栅设备(reference rasterizer device),即REF设备,它能以软件运算方式完全支持Direct3D API。
在Direct3D中,D3DDEVTYPE具有三种类型:
D3DDEVTYPE_HAL
D3DDEVTYPE_REF
D3DDEVTYPE_SW。
其中,D3DDEVTYPE_SW是一种外挂的Direct3D设备,用以支持第三方的软件。
二、COM
COM(Component Object Model,组件对象模型)是一项能够使DirectX独立于编程语言并具有向下兼容的技术。我们常称COM对象为接口,可将其视作为一个C++类来使用。我们所必需知道的仅仅是:
如何通过某个特定函数或另一个COM接口的方法来获取指向某一COM接口的指针
创建COM接口时不可以使用C++的关键字new
使用完一个接口,应该调用该接口相应的Release方法释放资源
注意:COM接口都有一个前缀I。例如IDirect3D9。
三、Direct3D初始化
Direct3D的初始化过程可以分解为如下四个步骤:
(1)获取接口IDirect3D9的指针。接口IDirect3D9用于获取系统中物理硬件设备的信息并创建接口IDirect3DDevice9,接口IDirect3DDevice9是一个C++对象,代表了我们用来显示3D图形的物理硬件设备。
(2)检查设备性能(D3DCAPS9),判断主显卡(primary display adapter 或 primary graphics card)是否支持硬件顶点运算。为了创建接口IDirect3DDevice9,我们必须明确显卡是否支持该功能。
(3)初始化D3DPRESENT_PARAMETERS结构的一个实例。该结构有许多数据成员组成,我们可以通过这些变量来指定即将创建的接口IDirect3DDevice9的特性。
(4)利用已初始化的D3DPRESENT_PARAMETERS结构创建IDirect3DDevice9对象。
一、获取接口IDirect3D9的指针
要初始化IDirect3D,首先必须获得指向接口IDirect3D9的指针。
if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))return E_FAIL;
函数Direct3DCreate9的参数必须是D3D_SDK_VERSION,只有如此方能保证应用程序使用正确的头文件。如果函数调用失败,将返回一个NULL指针。
IDirect3D9对象主要有两个用途:设备枚举(device enumeration)以及创建IDirect3DDevice9类型的对象。设备枚举是指获取系统中可用的每块图形卡的性能、显示模式、格式及其他信息。
二、校验硬件顶点运算
创建一个代表主显卡的IDirect3DDevice9类型对象时,必须指定使用该对象进行顶点运算的类型。如果可以,我们希望使用硬件顶点运算,但是由于并非所有的显卡都支持硬件顶点运算,我们必须首先检查图形卡是否支持该类型的运算。
GetDeviceCaps的声明如下:
HRESULT IDirect3D9::GetDeviceCaps(
UINT Adapter, //指定物理显卡的序号
D3DDEVTYPE DeviceType, //指定设备类型(D3DDEVTYPE_HAL 或者 D3DDEVTYPE_REF)
D3DCAPS9 * pCaps //返回已初始化的设备性能结构实例
);
D3DCAPS9 caps;g_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);int vp = 0;if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;elsevp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
三、填充D3DPRESENT_PARAMETERS结构
该结构用于指定 所要创建的IDirect3DDevice9类型对象的一些特性,该结构的定义如下:
typedef struct _D3DPRESENT_PARAMETERS_
{
UINT BackBufferWidth; //后台缓存中表面的宽度,单位为像素
UINT BackBufferHeight; //后台缓存中表面的高度,单位为像素
D3DFORMAT BackBufferFormat; //后台缓存的像素格式
UINT BackBufferCount; //所需使用的后台缓存的个数
D3DMULTISAMPLE_TYPE MultiSampleType; //后台缓存所使用的多重采样类型
DWORD MultiSampleQuality; //多重采样的质量水平
D3DSWAPEFFECT SwapEffect; //交换链中缓存页面的置换方式
HWND hDeviceWindow; //与设备相关的窗口句柄
BOOL Windowed; //为true时,表示窗口模式,为false时,表示全屏模式
BOOL EnableAutoDepthStencil; //为true时,则Direct3D自动创建并维护深度缓存或模版缓存
D3DFORMAT AutoDepthStencilFormat; //深度缓存或模版缓存的像素格式
DWORD Flags;
/* FullScreen_RefreshRateInHz must be zero for Windowed mode */
UINT FullScreen_RefreshRateInHz; //刷新频率
UINT PresentationInterval;
} D3DPRESENT_PARAMETERS;
{
UINT BackBufferWidth; //后台缓存中表面的宽度,单位为像素
UINT BackBufferHeight; //后台缓存中表面的高度,单位为像素
D3DFORMAT BackBufferFormat; //后台缓存的像素格式
UINT BackBufferCount; //所需使用的后台缓存的个数
D3DMULTISAMPLE_TYPE MultiSampleType; //后台缓存所使用的多重采样类型
DWORD MultiSampleQuality; //多重采样的质量水平
D3DSWAPEFFECT SwapEffect; //交换链中缓存页面的置换方式
HWND hDeviceWindow; //与设备相关的窗口句柄
BOOL Windowed; //为true时,表示窗口模式,为false时,表示全屏模式
BOOL EnableAutoDepthStencil; //为true时,则Direct3D自动创建并维护深度缓存或模版缓存
D3DFORMAT AutoDepthStencilFormat; //深度缓存或模版缓存的像素格式
DWORD Flags;
/* FullScreen_RefreshRateInHz must be zero for Windowed mode */
UINT FullScreen_RefreshRateInHz; //刷新频率
UINT PresentationInterval;
} D3DPRESENT_PARAMETERS;
该结构体填充的一个实例如下:
D3DPRESENT_PARAMETERS d3dpp;d3dpp.BackBufferWidth = width;d3dpp.BackBufferHeight = height;d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;d3dpp.BackBufferCount = 1;d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;d3dpp.MultiSampleQuality = 0;d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.hDeviceWindow = hwnd;d3dpp.Windowed = windowed;d3dpp.EnableAutoDepthStencil = true; d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;d3dpp.Flags = 0;d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
四、创建IDirect3DDevice9接口
CreateDevice函数的声明如下:
HRESULT IDirect3D9::CreateDevice(
UINT Adapter, //物理显卡序号
D3DDEVTYPEDeviceType, //设备类型(HAL 或者 REF)
HWND hFocusWindow, //与设备相关的窗口句柄
DWORD BehaviorFlags, //指定设备进行3D运算的工作方式
D3DPRESENT_PARAMETERS *pPresentationParameters, //D3DPRESENT_PATAMETERS类型实例
IDirect3DDevice9** ppReturnedDeviceInterface //返回创建的设备
);
创建实例如下:
if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,vp,&d3dpp, &g_pd3dDevice))){return E_FAIL;}
四、代码示例
代码说明:实现Direct3D的初始化,并将背景置为黄色
#include <Windows.h>
#include <mmsystem.h>
#include <d3dx9.h>
#pragma warning( disable : 4996 ) // disable deprecated warning
#include <strsafe.h>
#pragma warning( default : 4996 )
#include <d3dx9math.h>LPDIRECT3D9 g_pD3D = NULL;
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;HRESULT InitD3D(HWND hWnd)
{// Step1: Create the D3D object.if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))return E_FAIL;// Step 2: Check for hardware vp.D3DCAPS9 caps;g_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);int vp = 0;if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;elsevp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;// Step 3: Fill out the D3DPRESENT_PARAMETERS structure.D3DPRESENT_PARAMETERS d3dpp;ZeroMemory(&d3dpp, sizeof(d3dpp));d3dpp.Windowed = TRUE;d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;d3dpp.EnableAutoDepthStencil = TRUE;d3dpp.AutoDepthStencilFormat = D3DFMT_D16;// Step 4: Create the device.if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,vp,&d3dpp, &g_pd3dDevice))){return E_FAIL;}return S_OK;
}VOID Cleanup()
{if (g_pd3dDevice != NULL)g_pd3dDevice->Release();if (g_pD3D != NULL)g_pD3D->Release();
}VOID Render()
{g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255, 255, 0), 1.0f, 0);// Begin the sceneif (SUCCEEDED(g_pd3dDevice->BeginScene())){g_pd3dDevice->EndScene();}// Present the backbuffer contents to the displayg_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}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);
}INT WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, INT)
{UNREFERENCED_PARAMETER(hInst);// Register the window classWNDCLASSEX wc ={sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,GetModuleHandle(NULL), NULL, NULL, NULL, NULL,L"D3D Tutorial", NULL};RegisterClassEx(&wc);// Create the application's windowHWND hWnd = CreateWindow(L"D3D Tutorial", L"D3D : CreateDevice",WS_OVERLAPPEDWINDOW, 100, 100, 700, 700,NULL, NULL, wc.hInstance, NULL);// Initialize Direct3Dif (SUCCEEDED(InitD3D(hWnd))){// Show the windowShowWindow(hWnd, SW_SHOWDEFAULT);UpdateWindow(hWnd);// Enter the message loopMSG msg;ZeroMemory(&msg, sizeof(msg));while (msg.message != WM_QUIT){if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)){TranslateMessage(&msg);DispatchMessage(&msg);}elseRender();}}UnregisterClass(L"D3D Tutorial", wc.hInstance);return 0;
}
程序运行效果如下: