前言:
Direct3D是一套底层的API,即:应用程序接口。Direct3D主要用来开启硬件加速功能来绘制3D场景,它可以看做是应用程序和图形设备(3D硬件)交互的中介:
Application为应用程序;Direct3D为硬件定义好的、由Direct3D提供给应用程序的接口和函数。这些接口和函数就是当前版本Direct3D所支持的全部。
HAL为硬件抽象层,因为大家使用的图形卡不一定一样,各种图形卡的性能和功能机理也存在差异,所以,Direct3D无法直接和图形设备交互。HAL是一个指示设备完成某些操作的设备相关的代码集合,这样Direct3D就不用了解细节情况,可以独立于硬件之外。(但是要注意的是:设备制造商虽然把产品所能支持的功能都在HAL中实现,但是Direct3D支持、没在HAL中实现的功能是无法正确调用的)。
Direct3D初始化:
1.获取接口IDirect3D9的指针
2.检验设备性能
3.初始化D3DPRESENT_PARAMETER结构
4.创建IDirect3DDevice9对象
一、获取IDirect3D9指针
获取该指针需要使用一个函数:Direct3DCreate9(...)
获取方式:
IDirect3D9 *d3d9;
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
Direct3DCreate9函数的参数必须为D3D_SDK_VERSION,这样做的目的是保证应用程序使用正确的头文件。如果该函数调用失败,则返回一个NULL指针。
该IDirect3D9对象主要用于两点:
1.设备枚举。获取系统中可用的没块图形卡的性能、显式模式、格式等信息。
2.创建IdirectDDevice9类型的对象。
二、校验硬件顶点运算:
创建一个代表主显卡的IDirect3DDevice9类型的对象时,必须对该对象进行顶点运算检验。通常我们希望能够使用硬件顶点运算,(简单理解:采用硬件顶点运算效率高,而且解放了CUP,提高了性能)。但是并不是所有的显卡都支持硬件顶点运算。所以必须要进行检验:
D3DCAPS9 caps;
d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps);
int vp = 0;
if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
{
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
else
{
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
注意:这里将顶点运算的类型用vp保存,用于创建IDirect3DDevice类型对象时,对使用的顶点运算类型的指定。
三、填充D3DPRESENT_PARAMETER结构
该结构用于指定所要创建的IDirect3DDevice9类型对象的一些特性:
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接口
当D3DPRESENT_PARAMETER结构填充完毕后,我们可以通过CreateDevice函数来创建IDirect3DDevice9对象:
hr = d3d9->CreateDevice(
D3DADAPTER_DEFAULT,
deviceType,
hwnd,
vp,
&d3dpp,
device);
if( FAILED(hr) )
{
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
hr = d3d9->CreateDevice(
D3DADAPTER_DEFAULT,
deviceType,
hwnd,
vp,
&d3dpp,
device);
if( FAILED(hr) )
{
d3d9->Release();
::MessageBox(0, "CreateDevice() - FAILED", 0, 0);
return false;
}
}
完整代码(可运行):
#include<d3d9.h>
IDirect3DDevice9* Device = 0;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY: //销毁
PostQuitMessage(0);//终止请求
break;
case WM_KEYDOWN: //键按下
if (wParam == VK_ESCAPE)//Esc键
DestroyWindow(hwnd);
break;
}
//调用缺省的窗口过程来为应用程序没有处理的任何窗口消息提供缺省的处理。
//该函数确保每一个消息得到处理
return DefWindowProc(hwnd, msg, wParam, lParam);
}
bool InitD3D(HINSTANCE hInstance,int width, int height,bool windowed,D3DDEVTYPE deviceType,IDirect3DDevice9** device)
{
//定义窗口样式
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = "Direct3D9App";
//窗口注册
if (!RegisterClass(&wc))
{
MessageBox(0, "RegisterClass() - FAILED", 0, 0);
return false;
}
//创建窗口
HWND hwnd = 0;
hwnd = CreateWindow("Direct3D9App", "Direct3D9App",WS_OVERLAPPEDWINDOW, 0, 0, width, height,0 , 0 , hInstance, 0);
if (!hwnd)
{
MessageBox(0, "CreateWindow() - FAILED", 0, 0);
return false;
}
//绘制更新窗口
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
//--------以下为初始化IDirect3D------------
//获取IDirect3D9指针
IDirect3D9* d3d9 = 0;
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if (!d3d9)
{
MessageBox(0, "Direct3DCreate9() - FAILED", 0, 0);
return false;
}
//校验硬件顶点运算
D3DCAPS9 caps;
d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps);
int vp = 0;
if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
//填充D3DPRSENT_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;
//创建IDirectDevice9接口
d3d9->CreateDevice(D3DADAPTER_DEFAULT, deviceType,hwnd,vp,&d3dpp,device);
d3d9->Release();
return true;
}
int WINAPI WinMain(HINSTANCE hinstance,HINSTANCE prevInstance,PSTR cmdLine,int showCmd)
{
if (!InitD3D(hinstance,640, 480, true, D3DDEVTYPE_HAL, &Device))
{
MessageBox(0, "InitD3D() - FAILED", 0, 0);
return 0;
}
MSG msg;
ZeroMemory(&msg, sizeof(MSG)); //用0来填充消息可类比为:memset()函数
while (msg.message != WM_QUIT) //退出
{
//PeekMessage函数是以查看的方式从系统中获取消息
//并将该消息(如果存在)放于指定的结构
//PM_REMOVE:PeekMessage处理后,消息从队列里除掉。
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
//TranslateMessage函数将虚拟键消息转换为字符消息。
//字符消息被寄送到调用线程的消息队列里,
//当下一次线程调用函数GetMessage或PeekMessage时被读出。
//TranslateMessage只能用于转换调用GetMessage或PeekMessage接收的消息。
TranslateMessage(&msg);
//该函数分发一个消息给窗口程序。
//通常消息从GetMessage函数获得。
//消息被分发到回调函数(过程函数),作用是消息传递给操作系统,
//然后操作系统去调用我们的回调函数,也就是说我们在窗体的过程函数中处理消息
DispatchMessage(&msg);
}
else
{
if (Device)
{
Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
Device->Present(0, 0, 0, 0);
}
}
}
Device->Release();
return 0;
}