Direct3D是一套底层图形API,借助API,我们能够利用硬件加速功能绘制3D场景,Direct3D 可以被视为应用程序与图形设备交互式的中介,它们之前的关系可以描述如下
应用程序--->Direct3D--->HAL--->图形设备
在Direct3D和图形设备之间有一个中间环节,HAL(Hardware Abstraction Layer)由于市面上的图形卡品种繁多,每种卡性能和实现方式功能和机理都有差异,所以Direct3D无法与图形设备直接交互,所以Direct3D就需要设备制造商实现一个HAL,HAL是一个指示设备完成一些操作的代码集.
设备制造商将其产品所支持的全部功能都实现都到HAL中,那些,Direct3D支持,但是设备不支持的功能无法在HAL中实现,调用一个没有在HAL中实现的Direct3D函数将会导致调用失败,除非它是一个项点运算,并且用户已经指定了使用软件运算方式,在这种情况下,用户所期望的实现的功能便可Direct3D运算以软件方式来模拟.
1.REF设备
有时,D3D 提供的某些功能键不为您的图形设备支持,但您希望使用这些功能,为了满足这种需求,D3D提供了参考光栅设备(Reference rasterizer device) 也就是REF 设备,它能以软件运算方式完全支持D3D API,借助REF,您可以在代码中使用那些当前硬件不支持的特性,并对特性进行测试,注意REF设备仅用于开发阶段,它与DX SDK 捆绑在一起,无法发布给最终用户,此外REF速度十分缓慢,在测试以外的场合都不实用
2.D3DDEVTYPE
在程序代码中,HAL值用D3DDEVTYPE_HAL来指定,该值是D3DDEVTYPE枚举类型之一,REF值用D3DDEVTYPE_HAL来指定,全部类型值可以看SDK开发文档
二.Direct3D 的初始化
1.获取接口IDirect3D 的指针,该接口用于获取系统中物理设备的信息并创建接口IDirect3DDevice9,
2.检查设备性能,判断主显卡是否支持硬件顶点运算功能,
3.初始化D3DPRESENT_PARAMETERS结构,
4.创建IDirect3dDevice9对像
2.1获取接口IDirect3D9的指针
IDirect3D9 * g_d3d = Direct3DCreate9(D3D_SDK_VERSION)
2.2校验硬件顶点运算
IDirect3D9::GetDeviceCaps Method
函数原型如下
HRESULT GetDeviceCaps(
UINT Adapter, //指定的物理显示序号
D3DDEVTYPE DeviceType, //指定设备类型
D3DCAPS9 *pCaps //返回已初始化的设备性能结构实例
);
D3DCAPS9 caps;
d3d9->GetDeviceCaps(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
&caps
)
int vp = 0;
if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
{
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
else
{
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING
}
2.3填充D3DPRESENT_PARAMETER结构
该结构的定义如下
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;
BackBufferWidth, BackBufferHeight;// 后台缓存中表面的宽度,高度,单位为像素
BackBufferFormat;//后台缓存的像素格式
UINT BackBufferCount;//后台缓存的个数,通常指定为1
MultiSampleType;//多重采样类型(当SwapEffect=D3DSWAPEFFECT_DISCARD ,该值必须为 D3DMULTISAMPLE_NONE )
hDeviceWindow;//与设备相关的窗口
BOOL Windowed;//值为true时,表示为窗口模式,为false时为全屏模式
填充该结构的一个示例如下
D3DPRESENT_PARAMETER d3dpp;
d3dpp.BackBufferWidth = 800;
d3dpp.BackBufferHeight = 600;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
d3dpp.Windowed = true;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHZ = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRENT_INTERVAL_IMMEDIATE
2.4创建IDirect3DDevice9接口
该函数原型如下
HRESULT CreateDevice(
UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS *pPresentationParameters,
IDirect3DDevice9** ppReturnedDeviceInterface
);
其中DWORD BehaviorFlags值可以为
D3DCREATE_HARDWARE_VERTEXPROCESSING
D3DCREATE_SOFTWARE_VERTEXPROCESSING
示例如下
IDirect3DDevice9 *g_device;
g_d3d->CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hwnd,
D3DCRATE_HARDWARE_VERTEXPROCESSING,
&d3dpp,
&g_device
)
全部例子如下
#include
#include
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
LPDIRECT3D9 g_d3d;
LPDIRECT3DDEVICE9 g_device;
bool InitD3d(HWND hwnd,UINT width,UINT height)
{
g_d3d = Direct3DCreate9(D3D_SDK_VERSION);
if(g_d3d==NULL)
{
return false;
}
D3DDISPLAYMODE displaymode;
if(FAILED(g_d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&displaymode)))
{
return false;
}
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp,sizeof(d3dpp));
d3dpp.Windowed = true;
d3dpp.BackBufferWidth = width;
d3dpp.BackBufferHeight = height;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = displaymode.Format;
if(FAILED(g_d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,hwnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&d3dpp,&g_device)))
{
return false;
}
return true;
}
void RenderScene()
{
g_device->Clear(0,0,D3DCLEAR_TARGET,0xff000000,1.0f,0);
g_device->BeginScene();
//
g_device->EndScene();
g_device->Present(0,0,0,0);
}
void Shutdown()
{
if(g_d3d)
{
g_d3d->Release();
}
if(g_device)
{
g_device->Release();
}
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("DX SDK 9.0");
HWND hwnd;
MSG msg;
WNDCLASSEX wndclassex = {0};
wndclassex.cbSize = sizeof(WNDCLASSEX);
wndclassex.style = CS_HREDRAW | CS_VREDRAW;
wndclassex.lpfnWndProc = WndProc;
wndclassex.cbClsExtra = 0;
wndclassex.cbWndExtra = 0;
wndclassex.hInstance = hInstance;
wndclassex.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclassex.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclassex.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wndclassex.lpszMenuName = NULL;
wndclassex.lpszClassName = szAppName;
wndclassex.hIconSm = wndclassex.hIcon;
if (!RegisterClassEx (&wndclassex))
{
MessageBox (NULL, TEXT ("RegisterClassEx failed!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindowEx (WS_EX_OVERLAPPEDWINDOW,
szAppName,
TEXT ("WindowTitle"),
WS_OVERLAPPEDWINDOW,
100,
100,
800,
600,
NULL,
NULL,
hInstance,
NULL);
if(!InitD3d(hwnd,800,600))
return -1;
ShowWindow (hwnd, iCmdShow);
UpdateWindow (hwnd);
ZeroMemory(&msg,sizeof(msg));
while (msg.message!=WM_QUIT)
{
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
//
else
{
RenderScene();
}
}
Shutdown();
return msg.wParam;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage (0);
return (0);
}
return DefWindowProc (hwnd, message, wParam, lParam);
}