许可优化
产品
解决方案
服务支持
关于
软件库
当前位置:服务支持 >  软件文章 >  DirectX 3D编程及其最简单例子

DirectX 3D编程及其最简单例子

阅读数 9
点赞 0
article_banner

原文地址:http://blog.csdn.net/handsome0916/article/details/4636825

界面编程一直是程序员的一个比较高的门槛,Windows上最强大的3D库DirectX和开源的OpenGL库虽然强大,但是资料寥寥无几。再加上其复杂的变量类型和结构体,很多人望而却步。

大名鼎鼎的魔兽争霸是基于DirectX库上运行的,而反恐精英则使用了OpenGL技术。在图形界面的运行效率上,原来Windows自带的底层GDI库我认为已经比较高效,但DirectX却更神奇。DirectX有强大的图形库,直接和显卡的GPU打交道,而且封装了非常复杂繁琐的操作指令,我个人比较喜研究神奇的技术。

我也是DirectX的一名初学者,假如你对DirectX已经很熟,本文没有什么参考价值。由于水平有限,所以可能会有说错的地方。

一年前在网上搜了一下,DirectX的资料实在少得可怜。英文版的实在难看,于是在网上直接下载了个Microsoft DirectX SDK (April 2006),期待在帮助中找到例子。

Microsoft DirectX SDK (April 2006)的帮助有C++和.Net的例子,C++的例子都能编译通过, 但是VS2008对DirectX的兼容性好像不是很好。使用VS2008打开.net的例子需要版本转换,转换后编译不通过,在他的例子里修改了一下,好不容易通过了,但是下一个例子又要改。

最近重拾对DirectX的兴趣,到微软网站下载了最新的SDK,Microsoft DirectX SDK (August 2009)。这个版本的例子和帮助中,直接去掉了.Net的例子。可能是由于我水平问题没有下载对的版本,也可能是.net对DirectX的调用还不是很方便,于是看来学DirectX,没有什么捷径好走了,还得去面对复杂而高效的C++。

我在微软的官方网站上下载DirectX的SDK是不用收费的,大家大可不用第一时间考虑有没有试用版,直接到官方网站下载。http://www.microsoft.com/directx ,下载最新版本。

学习DirectX比较好的教程应该是Andy Pike写的教程,但那是针对老版本的DirectX 8,而且是英文的。网上有Aman JIANG将它的教程译成中文的版本,大家可以去搜搜。

安装了SDK后,有一些简单的例子。但是微软认为简单的例子对于DirectX的初学者来说,一点也不简单,因为它们为20多个例子写了一个通用框架,20多个例子都去调用这些公共类,这个通用框架很多东西是对于最简单的例子是没有必要的,影响了代码的阅读性。这个我和Aman JIANG一样的认为。所以对于DirectX初学者来说,SDK的帮助其实帮助不大。假如你的水平非常高,可以阅读使用它自带的例子,它的例子有VS2005和VS2008两个版本,大家可以用VS2005和VS2008这两个编辑工具直接打开对应的例子去阅读,假如你用惯了VS6.0,那么也可以用VS6.0去编写,头文件和库文件在安装目录的include和lib目录,记得要附加编译才能通过。

于是我还是回到最原始,使用Andy Pike的最原始例子,建立最原始的win32程序,使用DirectX的最简单的函数,最后是编译通过了,但是要注意,Andy Pike的例子仅仅是DirectX8的,我们下载的是最新的DirectX9 ,10 ,11的SDK,已经没有DirectX8的库了,所以我们能要做相应的修改。

下面我以一个不断旋转的正方体做一个例子,附上全部代码:(对Andy Pike的DX8的例子作了相应版本转换的修改)

阅读本例子需要一定的win32的编程基础,假如你不熟悉,很难看懂此代码,可以到我的上一篇文章去把win32的编程基础看懂。

  1. #pragma comment(lib,"d3d9.lib")
  2. #pragma comment(lib,"d3dx9.lib")
  3. #include <d3dx9.h>
  4. //d3dx8.lib d3d8.lib
  5. LPDIRECT3D9 g_pD3D = NULL;
  6. LPDIRECT3DDEVICE9 g_pD3DDevice = NULL;
  7. LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer = NULL; // Buffer to hold vertices
  8. struct CUSTOMVERTEX
  9. {
  10. FLOAT x, y, z;
  11. DWORD colour;
  12. };
  13. #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
  14. #define SafeRelease(pObject) if(pObject != NULL) {pObject->Release(); pObject=NULL;}
  15. HRESULT InitialiseD3D(HWND hWnd)
  16. {
  17. //First of all, create the main D3D object. If it is created successfully we
  18. //should get a pointer to an IDirect3D8 interface.
  19. g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
  20. if(g_pD3D == NULL)
  21. {
  22. return E_FAIL;
  23. }
  24. //Get the current display mode
  25. D3DDISPLAYMODE d3ddm;
  26. if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm)))
  27. {
  28. return E_FAIL;
  29. }
  30. //Create a structure to hold the settings for our device
  31. D3DPRESENT_PARAMETERS d3dpp;
  32. ZeroMemory(&d3dpp, sizeof(d3dpp));
  33. //Fill the structure.
  34. //We want our program to be windowed, and set the back buffer to a format
  35. //that matches our current display mode
  36. d3dpp.Windowed = TRUE;
  37. //d3dpp.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC;
  38. d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
  39. d3dpp.BackBufferFormat = d3ddm.Format;
  40. //Create a Direct3D device.
  41. if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
  42. D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice)))
  43. {
  44. return E_FAIL;
  45. }
  46. //Turn on back face culling. This is becuase we want to hide the back of our polygons
  47. g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
  48. //Turn off lighting becuase we are specifying that our vertices have colour
  49. g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
  50. return S_OK;
  51. }
  52. HRESULT InitialiseVertexBuffer()
  53. {
  54. VOID* pVertices;
  55. //Store each point of the cube together with it's colour
  56. //Make sure that the points of a polygon are specified in a clockwise direction,
  57. //this is because anti-clockwise faces will be culled
  58. //We will use a three triangle strips to render these polygons (Top, Sides, Bottom).
  59. CUSTOMVERTEX cvVertices[] =
  60. {
  61. //Top Face
  62. {-5.0f, 5.0f, -5.0f, D3DCOLOR_XRGB(0, 0, 255),}, //Vertex 0 - Blue
  63. {-5.0f, 5.0f, 5.0f, D3DCOLOR_XRGB(255, 0, 0),}, //Vertex 1 - Red
  64. {5.0f, 5.0f, -5.0f, D3DCOLOR_XRGB(255, 0, 0),}, //Vertex 2 - Red
  65. {5.0f, 5.0f, 5.0f, D3DCOLOR_XRGB(0, 255, 0),}, //Vertex 3 - Green
  66. //Face 1
  67. {-5.0f, -5.0f, -5.0f, D3DCOLOR_XRGB(255, 0, 0),}, //Vertex 4 - Red
  68. {-5.0f, 5.0f, -5.0f, D3DCOLOR_XRGB(0, 0, 255),}, //Vertex 5 - Blue
  69. {5.0f, -5.0f, -5.0f, D3DCOLOR_XRGB(0, 255, 0),}, //Vertex 6 - Green
  70. {5.0f, 5.0f, -5.0f, D3DCOLOR_XRGB(255, 0, 0),}, //Vertex 7 - Red
  71. //Face 2
  72. {5.0f, -5.0f, 5.0f, D3DCOLOR_XRGB(0, 0, 255),}, //Vertex 8 - Blue
  73. {5.0f, 5.0f, 5.0f, D3DCOLOR_XRGB(0, 255, 0),}, //Vertex 9 - Green
  74. //Face 3
  75. {-5.0f, -5.0f, 5.0f, D3DCOLOR_XRGB(0, 255, 0),}, //Vertex 10 - Green
  76. {-5.0f, 5.0f, 5.0f, D3DCOLOR_XRGB(255, 0, 0),}, //Vertex 11 - Red
  77. //Face 4
  78. {-5.0f, -5.0f, -5.0f, D3DCOLOR_XRGB(255, 0, 0),}, //Vertex 12 - Red
  79. {-5.0f, 5.0f, -5.0f, D3DCOLOR_XRGB(0, 0, 255),}, //Vertex 13 - Blue
  80. //Bottom Face
  81. {5.0f, -5.0f, -5.0f, D3DCOLOR_XRGB(0, 255, 0),}, //Vertex 14 - Green
  82. {5.0f, -5.0f, 5.0f, D3DCOLOR_XRGB(0, 0, 255),}, //Vertex 15 - Blue
  83. {-5.0f, -5.0f, -5.0f, D3DCOLOR_XRGB(255, 0, 0),}, //Vertex 16 - Red
  84. {-5.0f, -5.0f, 5.0f, D3DCOLOR_XRGB(0, 255, 0),}, //Vertex 17 - Green
  85. };
  86. //Create the vertex buffer from our device.
  87. if(FAILED(g_pD3DDevice->CreateVertexBuffer(18 * sizeof(CUSTOMVERTEX),
  88. 0, D3DFVF_CUSTOMVERTEX,
  89. D3DPOOL_DEFAULT, &g_pVertexBuffer,NULL)))
  90. {
  91. return E_FAIL;
  92. }
  93. //Get a pointer to the vertex buffer vertices and lock the vertex buffer
  94. //if(FAILED(g_pVertexBuffer->Lock(0, sizeof(cvVertices), (BYTE**)&pVertices, 0)))
  95. if(FAILED(g_pVertexBuffer->Lock(0, sizeof(cvVertices), (void**)&pVertices, 0)))
  96. {
  97. return E_FAIL;
  98. }
  99. //Copy our stored vertices values into the vertex buffer
  100. memcpy(pVertices, cvVertices, sizeof(cvVertices));
  101. //Unlock the vertex buffer
  102. g_pVertexBuffer->Unlock();
  103. return S_OK;
  104. }
  105. void SetupRotation()
  106. {
  107. //Here we will rotate our world around the x, y and z axis.
  108. D3DXMATRIX matWorld, matWorldX, matWorldY, matWorldZ;
  109. //Create the transformation matrices
  110. D3DXMatrixRotationX(&matWorldX, timeGetTime()/400.0f);
  111. D3DXMatrixRotationY(&matWorldY, timeGetTime()/400.0f);
  112. D3DXMatrixRotationZ(&matWorldZ, timeGetTime()/400.0f);
  113. //Combine the transformations by multiplying them together
  114. D3DXMatrixMultiply(&matWorld, &matWorldX, &matWorldY);
  115. D3DXMatrixMultiply(&matWorld, &matWorld, &matWorldZ);
  116. //Apply the tansformation
  117. g_pD3DDevice->SetTransform(D3DTS_WORLD, &matWorld);
  118. }
  119. void SetupCamera()
  120. {
  121. //Here we will setup the camera.
  122. //The camera has three settings: "Camera Position", "Look at Position" and "Up Direction"
  123. //We have set the following:
  124. //Camera Position: (0, 0, -30)
  125. //Look at Position: (0, 0, 0)
  126. //Up direction: Y-Axis.
  127. D3DXMATRIX matView;
  128. D3DXMatrixLookAtLH(&matView, &D3DXVECTOR3(0.0f, 0.0f,-30.0f), //Camera Position
  129. &D3DXVECTOR3(0.0f, 0.0f, 0.0f), //Look At Position
  130. &D3DXVECTOR3(0.0f, 1.0f, 0.0f)); //Up Direction
  131. g_pD3DDevice->SetTransform(D3DTS_VIEW, &matView);
  132. }
  133. void SetupPerspective()
  134. {
  135. //Here we specify the field of view, aspect ration and near and far clipping planes.
  136. D3DXMATRIX matProj;
  137. D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, 1.0f, 1.0f, 500.0f);
  138. g_pD3DDevice->SetTransform(D3DTS_PROJECTION, &matProj);
  139. }
  140. void Render()
  141. {
  142. if(g_pD3DDevice == NULL)
  143. {
  144. return;
  145. }
  146. //Clear the backbuffer to black
  147. g_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
  148. //Begin the scene
  149. g_pD3DDevice->BeginScene();
  150. //Setup the rotation, camera, and perspective matrices
  151. SetupRotation();
  152. SetupCamera();
  153. SetupPerspective();
  154. //Rendering our objects
  155. //STDMETHOD(SetStreamSource)(THIS_ UINT StreamNumber,IDirect3DVertexBuffer9* pStreamData,UINT OffsetInBytes,UINT Stride) PURE;
  156. g_pD3DDevice->SetStreamSource(0, g_pVertexBuffer,0, sizeof(CUSTOMVERTEX));
  157. //g_pD3DDevice->SetVertexShader((IDirect3DVertexShader9*)D3DFVF_CUSTOMVERTEX);
  158. g_pD3DDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
  159. g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); //Top
  160. g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 8); //Sides
  161. g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 14, 2); //Bottom
  162. //End the scene
  163. g_pD3DDevice->EndScene();
  164. //Filp the back and front buffers so that whatever has been rendered on the back buffer
  165. //will now be visible on screen (front buffer).
  166. g_pD3DDevice->Present(NULL, NULL, NULL, NULL);
  167. }
  168. void CleanUp()
  169. {
  170. SafeRelease(g_pVertexBuffer);
  171. SafeRelease(g_pD3DDevice);
  172. SafeRelease(g_pD3D);
  173. }
  174. void GameLoop()
  175. {
  176. //Enter the game loop
  177. MSG msg;
  178. BOOL fMessage;
  179. PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE);
  180. while(msg.message != WM_QUIT)
  181. {
  182. fMessage = PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE);
  183. if(fMessage)
  184. {
  185. //Process message
  186. TranslateMessage(&msg);
  187. DispatchMessage(&msg);
  188. }
  189. else
  190. {
  191. //No message to process, so render the current scene
  192. Render();
  193. }
  194. }
  195. }
  196. //The windows message handler
  197. LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  198. {
  199. switch(msg)
  200. {
  201. case WM_DESTROY:
  202. PostQuitMessage(0);
  203. return 0;
  204. break;
  205. case WM_KEYUP:
  206. switch (wParam)
  207. {
  208. case VK_ESCAPE:
  209. //User has pressed the escape key, so quit
  210. DestroyWindow(hWnd);
  211. return 0;
  212. break;
  213. }
  214. break;
  215. }
  216. return DefWindowProc(hWnd, msg, wParam, lParam);
  217. }
  218. //Application entry point
  219. INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, INT)
  220. {
  221. //Register the window class
  222. WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_CLASSDC, WinProc, 0L, 0L,
  223. GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
  224. "DX Project 3", NULL};
  225. RegisterClassEx(&wc);
  226. //Create the application's window
  227. HWND hWnd = CreateWindow("DX Project 3", "www.andypike.com: Tutorial 3",
  228. WS_OVERLAPPEDWINDOW, 50, 50, 500, 500,
  229. GetDesktopWindow(), NULL, wc.hInstance, NULL);
  230. //Initialize Direct3D
  231. if(SUCCEEDED(InitialiseD3D(hWnd)))
  232. {
  233. //Show our window
  234. ShowWindow(hWnd, SW_SHOWDEFAULT);
  235. UpdateWindow(hWnd);
  236. //Initialize Vertex Buffer
  237. if(SUCCEEDED(InitialiseVertexBuffer()))
  238. {
  239. //Start game running: Enter the game loop
  240. GameLoop();
  241. }
  242. }
  243. CleanUp();
  244. UnregisterClass("DX Project 3", wc.hInstance);
  245. return 0;
  246. }
cpp
运行

游戏动起来是怎样实现的呢?为什么我们设计的模型能像电影那样动起来呢?

我们在main函数的最后,调用了一个自定义叫GameLoop的函数,通过死循环的方式不断去调用自定义的Render函数名的函数,去刷新屏幕的显示。

其实游戏跟电影一样,也是这样将画面快速地更换,加上DirectX绘画的高效性,我们感觉不到画面其实是一卡一卡的。

DX界面的一个很重要的概念是设备(device)g_pD3DDevice,其实跟我们平时用到的GDI的DC类似,设备就是一个要绘制的对象,我们将画面绘制到设备上。

好了,这几乎是最简单的例子了,在SDK上所谓最简单的例子,其实比这个要复杂很多。初学者可以用这个作为最基本框架,作为参考去读它自带的更接近应用的框架。

值得注意的是,DX 的3D的概念中,所有的3D图形都是由无数的三角形组成,一个圆球其实也是用无数个三角形构成,三角形越多,效果越平滑,跟数学上曲线是由无数折线构成的原理是一样的,当然,三角形越多消耗的GPU的处理时间当然也越多。假如你的立体几何的逻辑建模能力非常优秀,不用任何3D 建模工具都能通过无数个三角形和颜色组合构建出一个物件或者人物,但我想,应该没有这么牛比的人吧。



免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删
相关文章
QR Code
微信扫一扫,欢迎咨询~

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 155-2731-8020
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

手机不正确

公司不为空