一.简介
二.Direct3D类
1.创建D3D类
IDirect3D9* WINAPI Direct3DCreate9(UINT SDKVersion);
//Direct3D类的创建 IDirect3D9* d3d9=0; d3d9=Direct3DCreate9(D3D_SDK_VERSION);
2.获取设备类型
STDMETHOD(GetDeviceCaps)(
THIS_ UINT Adapter, //设备显示器(显卡)
D3DDEVTYPE DeviceType, //要获取的设备类型
D3DCAPS9* pCaps //要获取的设备参数
) PURE;
- Adapter
D3DADAPTER_DEFAULT
- DeviceType
D3DDEVTYPE_HAL
D3DDEVTYPE_REF
D3DCAPS9 caps; D3DDEVTYPE deviceType; d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps);
3.判断显卡是否支持硬件加速
D3DCAPS9是设备参数结构体,不仅可以用来获取设备类型还可以用来判断是否支持硬件加速
int vp=0; if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) vp=D3DCREATE_HARDWARE_VERTEXPROCESSING; else vp=D3DCREATE_SOFTWARE_VERTEXPROCESSING;
4.填充显示参数结构体
typedef struct _D3DPRESENT_PARAMETERS_{
UINT BackBufferWidth; //后台缓冲区宽度
UINT BackBufferHeight; //后台缓冲区高度
D3DFORMAT BackBufferFormat; //后台缓冲区像素格式
UINT BackBufferCount; //后台缓冲区数量
D3DMULTISAMPLE_TYPE MultiSampleType; //多重采样类型
DWORD MultiSampleQuality; //多重采样质量
D3DSWAPEFFECT SwapEffect; //缓冲区的交换方式
//Direct3D用交换链来交替两帧之间的过渡,用IDirect3DSwapChain接口来表示
HWND hDeviceWindow; //窗口句柄
BOOL Windowed; //全屏或者窗口
BOOL EnableAutoDepthStencil; //是否开启深度缓存和模板缓存
//深度缓存是一个表面,担不是存储图像数据而是用来记录像素深度信息,用来确定物体的前后关系正确绘制的z-buffering技术
D3DFORMAT AutoDepthStencilFormat; //指定深度缓冲及模板缓冲区的格式
DWORD Flags; //其他的附加特性标志(通常指定为0或NULL)
UINT FullScreen_RefreshRateInHz; //指定屏幕的刷新频率
UINT PresentationInterval; //指定屏幕的翻转模式
}D3DPRESENT_PARAMETERS;
- BackBufferFormat
D3DFMT_UNKOWN:默认
D3DFMT_R8G8B8:表示24为像素
D3DFMT_X8R8G8B8:表示一个32为像素
- Multisampling
D3DMULTISAMPLE_NONE:不使用全屏抗锯齿
D3DMULTISAMPLE_1_SAMPLE - D3DMULTISAMPLE_16_SAMPLE:设定1-16级
- SwapEffect
D3DSWAPEEFECT_COPY :swap时,拷贝后缓冲区的内容到前缓冲区,后缓冲区的内容不变。
D3DSWAPEEFECT_FLIP :swap时,交换前后缓冲区指针,完成翻页,之后后缓冲区的内容是前缓冲区的内容
D3DSWAPEEFECT_DISCARD:可能是COPY也可能是FLIP,由设备来确定最适合当前情况的方式。
D3DSWAPEFFECT_DISCARD:清除后台缓存的内容
D3DSWAPEEFECT_FLIP:保留后台缓存的内容。当缓存区>1时。
D3DSWAPEFFECT_COPY: 保留后台缓存的内容,缓冲区=1时。
- AutoDepthStencilFormat
D3DFMT_D32:指定一个32位的深度缓冲区
D3DFMT_D24S8:指定一个32位的深度/模板缓冲区,其中24位用于深度缓冲区,8位用于模板缓冲区
D3DFMT_D24X8:指定一个32位的深度/模板缓冲区,其中24位用于的度缓冲区,8位空闲
D3DFMT_D24X4S4:指定一个32位的深度/模板缓冲区,其中24位用于深度缓冲区,4位用于模板缓冲区,4位空闲
D3DFMT_D16:指定一个16位的深度缓存区
D3DFMT_D15S1:指定一个16位的深度/模板缓冲区,其中15位用于深度缓冲区,1位用于模板缓冲区
- Flags
D3DPRESENTFLAG_LOCKABLE_BACKBUFFER:表示后缓冲区可以被锁定,需要注意的是这样缓冲区会降低程序的运行效率。
D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL:指定深度缓冲区和模板缓冲区在后一个缓冲区被渲染(即调用Present方法后)的时候将被释放
- FullScreen_RefreshRateInHz
在窗口模式下,必须指定为0或D3DPRESENT_RATE_DEFAULT(即默认的),表示使用与当前屏幕相同的刷新率)
D3DPRESENT_RATE_DEFAULT:表示使用默认刷新率,即与屏幕刷新率相同。
D3DPRESENT_RATE_UNLIMITED:表示图形绘制结束后立刻将内容复制到前台缓冲区。
- PresentationInterval
在窗口模式下,其取值为0,只能选用D3DPRESENT_INTERVAL_DEFAULT
D3DPRESENT_INTERVAL_DEFAULT:D3D选择交换频率,通常等同于屏幕刷新率
D3DPRESENT_INTERVAL_IMMEDIATE:立即显示更新(或立即交换),不推荐
D3DPRESENT_INTERVAL_ONE:等待一个垂直扫描周期才更新,有助于减少剪断和撕裂效果(其实DEFAULT和ONE完全无区别)
D3DPRESENT_INTERVAL_TWO~FOUR:分别对应等待相应个数周期才更新
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;
5.创建D3D设备类
HRESULT CreateDevice(
UINT Adapter, //默认显示适配器(显卡)
D3DDEVTYPE DeviceType, //设备类型
HWND hFocusWindow, //窗口句柄
DWORD BehaviorFlags, //是否支持硬件顶点处理的枚举值
D3DPRESENT_PARAMETERS *pPresentationParameters, //显示参数结构体
IDirect3DDevice9** ppReturnedDeviceInterface //要创建的D3D设备类
);
//Direct3D设备类的创建 IDirect3DDevice9* Device=0; HRESULT hr=d3d9->CreateDevice( D3DADAPTER_DEFAULT, deviceType, hwnd, vp, &d3dpp, device);
五.完整版示例
1.d3dUntility.h
////////////////////////////////////////////////////////////////////////////////////////////////// // // File: d3dUtility.h // // Author: Frank Luna (C) All Rights Reserved // // System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 // // Desc: Provides utility functions for simplifying common tasks. // ////////////////////////////////////////////////////////////////////////////////////////////////// #ifndef __d3dUtilityH__ #define __d3dUtilityH__ #include <d3dx9.h> #include <string> #include <tchar.h> #pragma comment(lib,"d3d9.lib") #pragma comment(lib,"winmm.lib") #pragma comment(lib,"d3dx9.lib") namespace d3d { bool InitD3D( HINSTANCE hInstance, // [in] Application instance. int width, int height, // [in] Backbuffer dimensions. bool windowed, // [in] Windowed (true)or full screen (false). D3DDEVTYPE deviceType, // [in] HAL or REF IDirect3DDevice9** device);// [out]The created device. int EnterMsgLoop( bool (*ptr_display)(float timeDelta)); LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); template<class T> void Release(T t) { if( t ) { t->Release(); t = 0; } } template<class T> void Delete(T t) { if( t ) { delete t; t = 0; } } } #endif // __d3dUtilityH__
2.d3dUntility.cpp
////////////////////////////////////////////////////////////////////////////////////////////////// // // File: d3dUtility.cpp // // Author: Frank Luna (C) All Rights Reserved // // System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 // // Desc: Provides utility functions for simplifying common tasks. // ////////////////////////////////////////////////////////////////////////////////////////////////// #include "d3dUnitility.h" bool d3d::InitD3D( HINSTANCE hInstance, int width, int height, bool windowed, D3DDEVTYPE deviceType, IDirect3DDevice9** device) { // // Create the main application window. // WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)d3d::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 = _T("Direct3D9App"); if( !RegisterClass(&wc) ) { ::MessageBoxA(0, "RegisterClass() - FAILED", 0, 0); return false; } HWND hwnd = 0; hwnd = ::CreateWindow(_T("Direct3D9App"), _T("Direct3D9App"), WS_EX_TOPMOST, 0, 0, width, height, 0 /*parent hwnd*/, 0 /* menu */, hInstance, 0 /*extra*/); if( !hwnd ) { ::MessageBoxA(0, "CreateWindow() - FAILED", 0, 0); return false; } ::ShowWindow(hwnd, SW_SHOW); ::UpdateWindow(hwnd); // // Init D3D: // HRESULT hr = 0; // Step 1: Create the IDirect3D9 object. IDirect3D9* d3d9 = 0; d3d9 = Direct3DCreate9(D3D_SDK_VERSION); if( !d3d9 ) { ::MessageBoxA(0, "Direct3DCreate9() - FAILED", 0, 0); return false; } // Step 2: Check for hardware vp. 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; // Step 3: Fill out the D3DPRESENT_PARAMETERS structure. 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; // Step 4: Create the device. hr = d3d9->CreateDevice( D3DADAPTER_DEFAULT, // primary adapter deviceType, // device type hwnd, // window associated with device vp, // vertex processing &d3dpp, // present parameters device); // return created device if( FAILED(hr) ) { // try again using a 16-bit depth buffer d3dpp.AutoDepthStencilFormat = D3DFMT_D16; hr = d3d9->CreateDevice( D3DADAPTER_DEFAULT, deviceType, hwnd, vp, &d3dpp, device); if( FAILED(hr) ) { d3d9->Release(); // done with d3d9 object ::MessageBoxA(0, "CreateDevice() - FAILED", 0, 0); return false; } } d3d9->Release(); // done with d3d9 object return true; } int d3d::EnterMsgLoop( bool (*ptr_display)(float timeDelta) ) { MSG msg; ::ZeroMemory(&msg, sizeof(MSG)); static float lastTime = (float)timeGetTime(); while(msg.message != WM_QUIT) { if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } else { float currTime = (float)timeGetTime(); float timeDelta = (currTime - lastTime)*0.001f; ptr_display(timeDelta); lastTime = currTime; } } return msg.wParam; }
3.d3dInit.cpp
////////////////////////////////////////////////////////////////////////////////////////////////// // // File: d3dinit.cpp // // Author: Frank Luna (C) All Rights Reserved // // System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 // // Desc: Demonstrates how to initialize Direct3D, how to use the book's framework // functions, and how to clear the screen to black. Note that the Direct3D // initialization code is in the d3dUtility.h/.cpp files. // ////////////////////////////////////////////////////////////////////////////////////////////////// #include "d3dUnitility.h" #include <windows.h> // // Globals // IDirect3DDevice9* Device = 0; // // Framework Functions // bool Setup() { // Nothing to setup in this sample. return true; } void Cleanup() { // Nothing to cleanup in this sample. } bool Display(float timeDelta) { if( Device ) // Only use Device methods if we have a valid device. { // Instruct the device to set each pixel on the back buffer black - // D3DCLEAR_TARGET: 0x00000000 (black) - and to set each pixel on // the depth buffer to a value of 1.0 - D3DCLEAR_ZBUFFER: 1.0f. Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0); // Swap the back and front buffers. Device->Present(0, 0, 0, 0); } return true; } // // WndProc // LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_DESTROY: ::PostQuitMessage(0); break; case WM_KEYDOWN: if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); break; } return ::DefWindowProc(hwnd, msg, wParam, lParam); } // // WinMain // int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd) { if(!d3d::InitD3D(hinstance, 640, 480, true, D3DDEVTYPE_HAL, &Device)) { ::MessageBox(0, "InitD3D() - FAILED", 0, 0); return 0; } if(!Setup()) { ::MessageBox(0, "Setup() - FAILED", 0, 0); return 0; } d3d::EnterMsgLoop( Display ); Cleanup(); Device->Release(); return 0; }
三.简化版示例
因为完整版代码比较多理解有点难,所以有些不必要的可以去掉,这样我们写些例子的时候,也可以精简一些
我们用一个.cpp和一个.hpp就可以实现了,它把窗口的创建和显示图像隔离开
1.d3dInit_k5.cpp
#include "d3dInit_k5.hpp" LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); //函数开始 int WINAPI/*基本调用_stdcall*/ WinMain(HINSTANCE hInstance,/*当前运行程序的实例句柄*/ HINSTANCE hPrevInstance,/*前一个句柄,一般都是NULL*/ LPSTR lpCmdLine,/*命令行参数,以空终止的字符串*/ int nCmdShow /*显示方式*/) { //声明一个窗口类结构体 WNDCLASS wc = { 0 }; //WNDCLASSEX比WNDCLASS多两个参数 //wc.cbSize = sizeof(PWNDCLASSEX);//表示该结构体的字节数大小 wc.style = CS_HREDRAW | CS_VREDRAW; // 窗口的风格样式 水平大小或垂直大小变化发生重绘 wc.lpfnWndProc = WndProc;//窗口的回调函数,响应事件的系统触发函数 wc.cbClsExtra = 0; //窗口类附加内存 wc.cbWndExtra = 0; //窗口的附加内存 wc.hInstance = hInstance; //指定包含窗口过程的程序的实例句柄 wc.hIcon = LoadIcon(0,/*程序句柄加载系统图标第一个参数为NULL,加载用户图标第一个参数为实例句柄*/ IDI_APPLICATION/*系统图标,或用户图标路径字符串*/);//窗口类的图标资源句柄 wc.hCursor = LoadCursor(0, IDC_ARROW);//箭头光标用法同上 wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//背景画刷句柄 wc.lpszMenuName = 0; //指定菜单资源的名字,字符串形式 wc.lpszClassName = "Direct3D9App";//自定义的窗口类名字 //wc.hIconSm = 0;//托盘中应用程序的小图标 if (!RegisterClass(&wc)) { ::MessageBox(0, TEXT("RegisterClass() - FAILED"), 0, 0); return 0; } HWND hwnd = 0; hwnd = CreateWindow("Direct3D9App",//对应窗口类的名称 "K5窗口", //指定创建的窗口名字 WS_MAXIMIZEBOX, //创建窗口的样式 CW_USEDEFAULT, //水平位置 CW_USEDEFAULT, //竖直位置 width, //宽 height, //高 0 /*父窗口的句柄*/, 0 /* 菜单资源句柄 */, hInstance, //程序实例句柄 0 /*WM_CREATE消息lParam数据指针*/); if (!hwnd) { ::MessageBox(0, TEXT("CreateWindow() - FAILED"), 0, 0); return 0; } ::ShowWindow(hwnd, SW_SHOW); ::UpdateWindow(hwnd); Cd3d d3d; d3d.InitD3D(hwnd); //消息循环 MSG msg = { 0 }; float lastTime = (float)timeGetTime(); while (msg.message != WM_QUIT) { if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { float curTime = (float)timeGetTime(); float timeDelta = (curTime - lastTime)*0.001f; if (Device) { d3d.RenderD3D(); } lastTime = curTime; } } UnregisterClass("Direct3D9App",wc.hInstance); return 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) ::DestroyWindow(hwnd); break; } return ::DefWindowProc(hwnd, msg, wParam, lParam); }
2.d3dInit_k5.hpp
#include <Windows.h> #include <d3d9.h> #include <d3dx9.h> #pragma comment(lib,"d3d9.lib") #pragma comment(lib,"d3dx9.lib") #pragma comment(lib,"winmm.lib") //声明 const int width = 800; const int height = 600; IDirect3DDevice9* Device = 0; D3DDEVTYPE deviceType = D3DDEVTYPE_HAL; class Cd3d{ public: bool InitD3D(HWND hwnd); void RenderD3D(); }; bool Cd3d::InitD3D(HWND hwnd){ //初始化DirectX HRESULT hr = 0; IDirect3D9* d3d9 = 0; d3d9 = Direct3DCreate9(D3D_SDK_VERSION); if (!d3d9) { ::MessageBox(0, TEXT("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; 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 = true;//true为窗口模式,false则为全屏模式 d3dpp.EnableAutoDepthStencil = true;//设为true,D3D将自动创建深度/模板缓冲 d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;//深度/模板缓冲的格式 d3dpp.Flags = 0; //一些附加特性,设为0或者D3DPRESENTFLAG类型的一个成员,一个表面能够被锁定,降低程序的性能,一个深度/模板缓冲调用present后会被删除,提升程序性能 d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;//刷新频率 d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;//交换方式(D3DPRESENT_INTERVAL_IMMEDIATE立即交换,D3DPRESENT_INTERVAL_DEFAULT 等于刷新频率) hr = d3d9->CreateDevice( D3DADAPTER_DEFAULT, // 指定对象要表示的物理显示设备 deviceType, // 设备类型 hwnd, // 设备的窗口句柄 vp, // 采用硬件顶点处理或者软件顶点处理 &d3dpp, // 初始化好的D3DPRESENT_PARAMETERS实例 &Device); // 返回创建的设备 if (FAILED(hr)) { // try again using a 16-bit depth buffer d3dpp.AutoDepthStencilFormat = D3DFMT_D16; hr = d3d9->CreateDevice( D3DADAPTER_DEFAULT, deviceType, hwnd, vp, &d3dpp, &Device); if (FAILED(hr)) { d3d9->Release(); // done with d3d9 object ::MessageBox(0, TEXT("CreateDevice() - FAILED"), 0, 0); return 0; } } else{ //开始设置参数 } d3d9->Release(); // done with d3d9 object return true; } void Cd3d::RenderD3D(){ Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffff0000, 1.0f, 0); //开始显示 Device->Present(0, 0, 0, 0); }