- A+
首先,在Win32项目中引入Direct3D
这里使用最简单的方法
因为vs2015已经带有了DirectX
先引入头文件,在动态链接库文件
1 2 |
#include<d3d9.h> #pragma comment(lib,"d3d9.lib") |
这里使用Direct9
是因为它兼容大多数的Windows系统
然后,自定义窗口,消息循环等
详情:http://chicai.applinzi.com/?p=44
开始初始化
创建两个全局变量
1 2 |
LPDIRECT3D9 d3d = NULL; LPDIRECT3DDEVICE9 d3ddev = NULL; |
d3d是用于初始化创建设备
d3ddev设备,用于渲染
初始化如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
bool Game_Init(HWND hwnd) { d3d = Direct3DCreate9(D3D_SDK_VERSION); if (d3d == NULL) { MessageBox(hwnd, L"Error initializing Direct3D", L"Error", MB_OK); return false; } D3DDISPLAYMODE dm; d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dm); D3DPRESENT_PARAMETERS d3dpp = { 0 }; ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = dm.Format; d3dpp.BackBufferCount = 1; d3dpp.BackBufferHeight = dm.Height; d3dpp.BackBufferWidth = dm.Width; d3dpp.Windowed = FALSE; d3dpp.hDeviceWindow = hwnd; d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); if (d3ddev == NULL) { MessageBox(hwnd, L"初始化Direct3D device失败", L"错误", MB_OK); return false; } return true; } |
1.函数原型:IDirect3D9 * WINAPI Direct3DCreate9(UINT SDKVersion)
该函数的参数必须是D3D_SDK_VERSION,
只有如此方能保证应用程序使用正确的头文件
2.
D3DDISPLAYMODE dm;
d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dm);
这里是获取的是显示器的信息保存在dm中
3.
D3DPRESENT_PARAMETERS d3dpp = { 0 };
d3dpp是用于设定设备参数的
下面是参数们↓
(1)BackBufferWidth和BackBufferHeight:后备缓冲的宽度和高度。在全屏模式下,这两者的值必需符合显卡所支持的分辨率。例如(800,600),(640,480)。
(2)BackBufferFormat:后备缓冲的格式。这个参数是一个D3DFORMAT枚举类型,它的值有很多种,例如D3DFMT_R5G6B5,这说明后备缓冲的格式是每个像素16位,其实红色(R)占5位,绿色(G)占6位,蓝色(B)占5位,为什么绿色会多一位呢?据说是因为人的眼睛对绿色比较敏感。DX9只支持16位和32位的后备缓冲格式,24位并不支持。如果对这D3DFORMAT不熟悉的话,可以把它设为D3DFMT_UNKNOWN,这时候它将使用桌面的格式。(3)BackBufferCount:后备缓冲的数目,范围是从0到3,如果为0,那就当成1来处理。大多数情况我们只使用一个后备缓冲。使用多个后备缓冲可以使画面很流畅,但是却会造成输入设备响应过慢,还会消耗很多内存。
(4)MultiSampleType和MultiSampleQuality:这两个参数可以使你的渲染场景变得更好看,但是却消耗你很多内存资源,而且,并不是所有的显卡都支持这两者的所设定的功能的。在这里我们分别把它们设为D3DMULTISAMPLE_NONE和0。
(5) SwapEffect:交换缓冲支持的效果类型。它是D3DSWAPEFFECT枚举类型,可以设定为以下三者之一:D3DSWAPEFFECT_DISCARD,D3DSWAPEFFECT_FLIP,D3DSWAPEFFECT_COPY。如果设定为D3DSWAPEFFECT_DISCARD,则后备缓冲区的东西被复制到屏幕上后,后备缓冲区的东西就没有什么用了,可以丢弃(discard)了。如果设定为D3DSWAPEFFECT_FLIP,则表示在显示和后备缓冲之间进行周期循环。设定D3DSWAPEFFECT_COPY的话,我也不太清楚有什么作用*^_^*。一般我们是把这个参数设为D3DSWAPEFFECT_DISCARD。
(6)hDeviceWindow:显示设备输出窗口的句柄
(7) Windowed:如果为FALSE,表示要渲染全屏。如果为TRUE,表示要渲染窗口。渲染全屏的时候,BackBufferWidth和BackBufferHeight的值就得符合显示模式中所设定的值。
(8) EnableAutoDepthStencil:如果要使用Z缓冲,则把它设为TRUE。
(9)AutoDepthStencilFormat:如果不使用深度缓冲,那么这个参数将没有用。如果启动了深度缓冲,那么这个参数将为深度缓冲设定缓冲格式(和设定后备缓冲的格式差不多)
(10)Flags:可以设置为0或D3DPRESENTFLAG_LOCKABLE_BACKBUFFER。不太清楚是用来做什么的,看字面好像是一个能否锁定后备缓冲区的标记。
(11)FullScreen_RefreshRateInHz:显示器的刷新率,单位是HZ,如果设定了一个显示器不支持的刷新率,将会不能创建设备或发出警告信息。为了方便,一般设为D3DPRESENT_RATE_DEFAULT就行了。
(12)PresentationInterval:如果设置为D3DPRENSENT_INTERVAL_DEFAULT,则说明在显示一个渲染画面的时候必要等候显示器刷新完一次屏幕。例如你的显示器刷新率设为80HZ的话,则一秒内你最多可以显示80个渲染画面。另外你也可以设置在显示器刷新一次屏幕的时间内显示1到4个画面。如果设置为D3DPRENSENT_INTERVAL_IMMEDIATE,则表示可以以即时的方式来显示渲染画面,虽然这样可以提高帧速(FPS),但是却会产生图像撕裂的情况。
使用前先ZeroMemory(&d3dpp, sizeof(d3dpp));
初始化此结构的值,不然会出错
CreateDevice创建设备函数
HRESULT CreateDevice(
UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS *pPresentationParameters,
IDirect3DDevice9** ppReturnedDeviceInterface
);
参数
Adapter:
序数所指示的显示器适配器。D3DADAPTER_DEFAULT始终是主要的显示器适配器。
DeviceType:
在D3DDEVTYPE列举的成员,表示预设类型的驱动器类型,在HAL(Hardware Accelerator,硬件加速)和REF(Reference Rasterizer,一调试工具)之间选择。这里有第三个选项,软件渲染,作用是设计能支持自定义渲染的插件。DirectX DDK(驱动程序开发工具包)就能做到,但如果你能自己写出3D渲染器的话,是不太可能使用VB的J……请指定参数D3DDEVTYPE_HAL(硬件加速)或D3DDEVTYPE_REF(软件模拟) 。,如果预设的设备类型是无效的,即如果不支持硬件加速,调用此函数就会失败,你就不能创建设备。
hFocusWindow:
与设备相关的窗口句柄,你想在哪个窗口绘制就写那个窗口的句柄
BehaviorFlags:
设定为D3DCREATE_SOFTWARE_VERTEXPROCESSING(软件顶点处理) 或者D3DCREATE_HARDWARE_VERTEXPROCESSING(硬件顶点处理) ,使用前应该用d3dcaps来检测用户计算机是否支持硬件顶点处理功能。
PresentationParameters:
一个D3DPRESENT_PARAMETERS 类型的变量,用于指定将要创建设备的各种信息
ppReturnedDeviceInterface:
一个DIRECT3DDEVICE9类型的指针用来返回创建的设备
设备的简单使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void Game_Run(HWND hwnd) { if (!d3ddev) return; d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 0, 255), 1.0f, 0); if (d3ddev->BeginScene()) { //doingsomething //stop rendering d3ddev->EndScene(); d3ddev->Present(NULL, NULL, NULL, NULL); } if (KEY_DOWN(VK_ESCAPE)) { PostMessage(hwnd, WM_DESTROY, 0, 0); } } |
功能:将一些可用的Buffer清理干净。
函数原型:
1234567 HRESULT Clear(DWORD Count,const D3DRECT *pRects,DWORD Flags,D3DCOLOR Color,float Z,DWORD Stencil);
1 例: pd3dDevce->clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER ,D3DCOLOR_ARGB(0,45,50,170),1.0F.0);第一个参数:告诉系统有多少个矩形区域要被clear。
第二个参数:说明这些要被clear的矩形数组的指针。
注:如果clear的范围是整个buffer,那么第一个参数值只要填0,第二个参数填NULL即可。
第三个参数:用来指定要被clear的是哪些buffer(可以是三个Buffer 的组合)。
注:D3D里相对于窗口画面用到的buffer有三种:color buffer 、depth buffer 、stencil buffer ;color buffer 用来呈现窗口上每个pixel的颜色值,
也就是实际见到的彩色画面,color buffer 又称Render Target;Depth Buffer又称Z Buffer;Stencil Buffer 是模板 、铸板的意思。
第四个参数:指定给Color Buffer的背景色;
第五个参数:给Depth Buffer 用的,只要pixel的Z值介于0~1,就会填入Depth Buffer;
第六个参数:指定给Stencil Buffer,上例中没用到Stencil buffer ,所以指定为0;
在D3D中,需要使用BeginScene和EndScene函数,然后所有的图元绘制代码才能被调用。通过了解,需要注意下下面一些问题:
1 BeginScene和EndScene必须成对实现。
2 BeginScene不能连续调用两次否则会出现调用异常。
3 EndScene属于作用是实际应用所有的绘制命令至显卡,但是它是异步执行的,即它会立即返回,但是不保证绘制命令执行完成。
4 Present函数会最终等待所有绘制命令结束并将结果从back buffer拷贝到front buffer。
5 BeginScene和EndScene之间的绘制代码量可以不要太多,当然太少也不好。这样才能保证最后的present不至于等待大量的CPU时间等显卡完成所有的绘制指令。这样可以在present之前多次使用BeginScene/EndScene队,保证CPU和GPU始终基本同时在工作(并行)。
6 如果确实存在BeginScene/EndScene之间绘制命令过多,可以在EndScene/Present之间添加一些CPU指令,避免CPU在Present时过多时间空等GPU完成绘制返回。
游戏结束的话,释放掉内存
1 2 3 4 5 6 7 8 9 10 11 12 |
void Game_End(HWND hwnd) { if (d3ddev) { d3ddev->Release(); d3ddev = NULL; } if (d3d) { d3d->Release(); d3d = NULL; } } |
最后
将这些函数,插入到Win32代码中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
... ShowWindow(hwnd, nShowCmd); UpdateWindow(hwnd); if (!Game_Init(hwnd)) return false; while (!gameover) { if (PeekMessage(&msg, NULL, 0, 0,PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } Game_Run(hwnd); } Game_End(hwnd); return 0; } |
声明:引用部分均来自网上