DirectX 3D编程入门教程(一)

发表于2017-09-12
评论0 1.42w浏览

本篇文章主要给大家介绍DirectX 3D编程入门教程系列,该教程适用于一些刚刚涉及DirectX 3D编程的朋友,可以让大家快速掌握,下面开始介绍第一篇。

环境配置以及背景知识

环境 
Windows 8.1 64bit 
VS2013 
Microsoft DirectX SDK (June 2010) 
NVDIA Geforce GT755

环境的配置参考 VS2008整合DirectX9.0开发环境


一些背景知识 


DirectX的和应用层与硬件层的关系如下


REF设备允许开发人员测试那些Direct3D提供了但未被图形设备所实现的功能。

COM(Component Object Model)是一项可使DirectX独立于编程语言,并具备向下兼容的技术。基本思想是将大而复杂的应用软件分为一系列的可现行实现,易于开发,理解复用和调整的软件单元。

COM组件是遵循COM规范编写,以Win32动态链接库(dll)或者可执行文件形式发布的可执行二进制代码(exe)。

COM的优点:

  • 与开发语言无关
  • 通过接口有效保证了组件的复用性
  • 组件运行效率高,便于使用和管理

下面可以正式开始今天的学习了。

绘制一个三角形

用到的DxUtility类在 VS2008整合DirectX9.0开发环境已经实现了,可以直接去看。主要修改一下渲染的几个函数。

  1. #include "dxutility.h"  
  2. #include   
  3. #include   
  4.   
  5. //  
  6. // Globals  
  7. //  
  8.   
  9. IDirect3DDevice9* Device = 0;  
  10. D3DXMATRIX World;  
  11. IDirect3DVertexBuffer9 * VB = 0;  
  12.   
  13. const int Width = 800;  
  14. const int Height = 600;  
  15.   
  16. struct Vertex{  
  17.     Vertex(){};  
  18.     Vertex(float _x, float _y, float _z)  
  19.     {  
  20.         x = _x;  
  21.         y = _y;  
  22.         z = _z;  
  23.     }  
  24.   
  25.     float x, y, z;  
  26.     static const DWORD FVF;  
  27. };  
  28.   
  29. const DWORD Vertex::FVF = D3DFVF_XYZ;  
  30.   
  31. //  
  32. // Framework Functions  
  33. //  
  34.   
  35. bool Setup()  
  36. {  
  37.     Device->CreateVertexBuffer(  
  38.         3 * sizeof(Vertex),  
  39.         D3DUSAGE_WRITEONLY,  
  40.         Vertex::FVF,  
  41.         D3DPOOL_MANAGED,  
  42.         &VB,  
  43.         0);  
  44.   
  45.     Vertex* vertices;  
  46.     VB->Lock(0, 0, (void**)&vertices, 0);  
  47.   
  48.     vertices[0] = Vertex(-1.0f, 0.0f, 2.0f);  
  49.     vertices[1] = Vertex(0.0f, 1.0f, 2.0f);  
  50.     vertices[2] = Vertex(1.0f, 0.0f, 2.0f);  
  51.   
  52.   
  53.     VB->Unlock();  
  54.   
  55.     D3DXMATRIX proj;  
  56.     D3DXMatrixPerspectiveFovLH(  
  57.         &proj,                        // result  
  58.         D3DX_PI * 0.5f,               // 90 - degrees  
  59.         (float)Width / (float)Height, // aspect ratio  
  60.         1.0f,                         // near plane  
  61.         1000.0f);                     // far plane  
  62.     Device->SetTransform(D3DTS_PROJECTION, &proj);  
  63.   
  64.     Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);  
  65.   
  66.     return true;  
  67. }  
  68.   
  69. void Cleanup()  
  70. {  
  71.     Dx::Release(VB);  
  72. }  
  73.   
  74. bool Display(float timeDelta)  
  75. {  
  76.     if (Device) // Only use Device methods if we have a valid device.  
  77.     {  
  78.         Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);  
  79.         Device->BeginScene();  
  80.   
  81.         Device->SetStreamSource(0, VB, 0, sizeof(Vertex));  
  82.         Device->SetFVF(Vertex::FVF);  
  83.   
  84.         // Draw one triangle.  
  85.         Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);  
  86.   
  87.         Device->EndScene();  
  88.         Device->Present(0, 0, 0, 0);  
  89.     }  
  90.   
  91.     return true;  
  92. }  
  93.   
  94. //  
  95. // WndProc  
  96. //  
  97. LRESULT CALLBACK Dx::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
  98. {  
  99.     switch (msg)  
  100.     {  
  101.     case WM_DESTROY:  
  102.         ::PostQuitMessage(0);  
  103.         break;  
  104.   
  105.     case WM_KEYDOWN:  
  106.         if (wParam == VK_ESCAPE)  
  107.             ::DestroyWindow(hwnd);  
  108.         break;  
  109.     }  
  110.     return ::DefWindowProc(hwnd, msg, wParam, lParam);  
  111. }  
  112.   
  113. //  
  114. // WinMain  
  115. //  
  116. int WINAPI WinMain(HINSTANCE hinstance,  
  117.     HINSTANCE prevInstance,  
  118.     PSTR cmdLine,  
  119.     int showCmd)  
  120. {  
  121.     if (!Dx::InitDx(hinstance,  
  122.         Width, Height, true, D3DDEVTYPE_HAL, &Device))  
  123.     {  
  124.         ::MessageBox(0, "InitD3D() - FAILED", 0, 0);  
  125.         return 0;  
  126.     }  
  127.   
  128.     if (!Setup())  
  129.     {  
  130.         ::MessageBox(0, "Setup() - FAILED", 0, 0);  
  131.         return 0;  
  132.     }  
  133.     Dx::EnterMsgLoop(Display);  
  134.   
  135.     Cleanup();  
  136.   
  137.     Device->Release();  
  138.   
  139.     return 0;  
  140. }  


最终效果 




给三角形加上颜色 
数据结构定义

  1. struct ColorVertex{  
  2.     ColorVertex(float _x, float _y, float _z, D3DCOLOR c)  
  3.     {  
  4.         x = _x;  
  5.         y = _y;  
  6.         z = _z;  
  7.         color = c;  
  8.     }  
  9.     float x, y, z;  
  10.     D3DCOLOR color;  
  11.     static const DWORD FVF;  
  12. };  
  13. const DWORD ColorVertex::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;  

创建Buffer

  1. Device->CreateVertexBuffer(  
  2.     3 * sizeof(ColorVertex),  
  3.     D3DUSAGE_WRITEONLY,  
  4.     ColorVertex::FVF,  
  5.     D3DPOOL_MANAGED,  
  6.     &VB,  
  7.     0);  
  8.   
  9. ColorVertex *v;  
  10. VB->Lock(0, 0, (void**)&v, 0);  
  11. v[0] = ColorVertex(-1.0f, 0.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0));  
  12. v[1] = ColorVertex(0.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(0, 255, 0));  
  13. v[2] = ColorVertex(1.0f, 0.0f, 2.0f, D3DCOLOR_XRGB(0, 0, 255));  
  14.   
  15. VB->Unlock();  

在绘制函数中设置使用Ground插值进行三角形绘制

  1. bool Display(float timeDelta)  
  2. {  
  3.     if (Device) // Only use Device methods if we have a valid device.  
  4.     {  
  5.         std::cout << "Display" << std::endl;  
  6.         Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);  
  7.         Device->BeginScene();  
  8.   
  9.         Device->SetStreamSource(0, VB, 0, sizeof(ColorVertex));  
  10.         Device->SetFVF(ColorVertex::FVF);  
  11.   
  12.         Device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);  
  13.         Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);  
  14.   
  15.         Device->EndScene();  
  16.         Device->Present(0, 0, 0, 0);  
  17.     }  
  18.   
  19.     return true;  
  20. }  


渲染结果 



绘制一个旋转的正方体

生成Vertex Buffer和Index Buffer

  1. Device->CreateVertexBuffer(  
  2.      8 * sizeof(ColorVertex),  
  3.      D3DUSAGE_WRITEONLY,  
  4.      ColorVertex::FVF,  
  5.      D3DPOOL_MANAGED,  
  6.      &VB,  
  7.      0);  
  8.  Device->CreateIndexBuffer(  
  9.      36 * sizeof(WORD),  
  10.      D3DUSAGE_WRITEONLY,  
  11.      D3DFMT_INDEX16,  
  12.      D3DPOOL_MANAGED,  
  13.      &IB,  
  14.      0);  
  15.   
  16.  ColorVertex *v;  
  17.  VB->Lock(0, 0, (void**)&v, 0);  
  18.  v[0] = ColorVertex(-1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(255, 0, 0));  
  19.  v[1] = ColorVertex(-1.0f, 1.0f, -1.0f, D3DCOLOR_XRGB(0, 255, 0));  
  20.  v[2] = ColorVertex(1.0f, 1.0f, -1.0f, D3DCOLOR_XRGB(0, 0, 255));  
  21.  v[3] = ColorVertex(1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(255, 255, 0));  
  22.  v[4] = ColorVertex(-1.0f, -1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0));  
  23.  v[5] = ColorVertex(-1.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255));  
  24.  v[6] = ColorVertex(1.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 255));  
  25.  v[7] = ColorVertex(1.0f, -1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0));  
  26.   
  27.  VB->Unlock();  
  28.   
  29.  WORD* indices = 0;  
  30.  IB->Lock(0, 0, (void**)&indices, 0);  
  31.  // front side  
  32.  indices[0] = 0; indices[1] = 1; indices[2] = 2;  
  33.  indices[3] = 0; indices[4] = 2; indices[5] = 3;  
  34.   
  35.  // back side  
  36.  indices[6] = 4; indices[7] = 6; indices[8] = 5;  
  37.  indices[9] = 4; indices[10] = 7; indices[11] = 6;  
  38.   
  39.  // left side  
  40.  indices[12] = 4; indices[13] = 5; indices[14] = 1;  
  41.  indices[15] = 4; indices[16] = 1; indices[17] = 0;  
  42.   
  43.  // right side  
  44.  indices[18] = 3; indices[19] = 2; indices[20] = 6;  
  45.  indices[21] = 3; indices[22] = 6; indices[23] = 7;  
  46.   
  47.  // top  
  48.  indices[24] = 1; indices[25] = 5; indices[26] = 6;  
  49.  indices[27] = 1; indices[28] = 6; indices[29] = 2;  
  50.   
  51.  // bottom  
  52.  indices[30] = 4; indices[31] = 0; indices[32] = 3;  
  53.  indices[33] = 4; indices[34] = 3; indices[35] = 7;  
  54.   
  55.  IB->Unlock();  



绘制函数,让正方体旋转起来

  1. // spin the cube:  
  2.  //  
  3.  D3DXMATRIX Rx, Ry;  
  4.   
  5.  // rotate 45 degrees on x-axis  
  6.  D3DXMatrixRotationX(&Rx, 3.14f / 4.0f);  
  7.   
  8.  // incremement y-rotation angle each frame  
  9.  static float y = 0.0f;  
  10.  D3DXMatrixRotationY(&Ry, y);  
  11.  y  = timeDelta;  
  12.   
  13.  // reset angle to zero when angle reaches 2*PI  
  14.  if (y >= 6.28f)  
  15.      y = 0.0f;  
  16.   
  17.  // combine x- and y-axis rotation transformations.  
  18.  D3DXMATRIX p = Rx * Ry;  
  19.   
  20.  Device->SetTransform(D3DTS_WORLD, &p);  
  21.   
  22.  Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);  
  23.  Device->BeginScene();  
  24.   
  25.  Device->SetStreamSource(0, VB, 0, sizeof(ColorVertex));  
  26.  Device->SetIndices(IB);  
  27.  Device->SetFVF(ColorVertex::FVF);  
  28.   
  29.   
  30.  Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);  
  31.   
  32.  Device->EndScene();  
  33.  Device->Present(0, 0, 0, 0);  



在屏幕上显示FPS信息 
首先初始化文字

  1. D3DXFONT_DESC d3dFont;  
  2.   
  3. memset(&d3dFont, 0, sizeof(d3dFont));  
  4. d3dFont.Height = 25; // in logical units  
  5. d3dFont.Width = 12; // in logical units  
  6. d3dFont.Weight = 500;// boldness, range 0(light) - 1000(bold)  
  7. d3dFont.Italic = FALSE;  
  8. d3dFont.CharSet = DEFAULT_CHARSET;  
  9. strcpy_s(d3dFont.FaceName, "Times New Roman");  
  10. if (FAILED(D3DXCreateFontIndirect(Device, &d3dFont, &font)))  
  11. {  
  12.     ::MessageBox(0, "D3DXCreateFontIndirect() - FAILED", 0, 0);  
  13.     ::PostQuitMessage(0);  
  14. }  



声明几个变量

  1. ID3DXFont* font = 0;  
  2. DWORD FrameCnt = 0;  
  3. float TimeElapsed = 0;  
  4. float FPS = 0;  
  5. char FPSString[16];  


FPS的计算 

  1. FrameCnt ;  
  2. TimeElapsed  = timeDelta;  
  3. if (TimeElapsed >= 1.0f)  
  4. {  
  5.     FPS = (float)FrameCnt / TimeElapsed;  
  6.     sprintf_s(FPSString, "FPS:%f", FPS);  
  7.     FPSString[15] = '\0'// mark end of string  
  8.     TimeElapsed = 0.0f;  
  9.     FrameCnt = 0;  
  10. }  


文字的渲染

  1. Device->BeginScene();  
  2. RECT rect = { 0, 0, Width, Height };  
  3. font->DrawText(  
  4.     m_pSprite,  
  5.     FPSString,  
  6.     -1, // size of string or -1 indicates null terminating string  
  7.     &rect, // rectangle text is to be formatted to in windows coords  
  8.     DT_TOP | DT_LEFT, // draw in the top left corner of the viewport  
  9.     0xff000000);      // black text  
  10.   
  11. Device->EndScene();  


记住最后要Clear掉COM对象

  1. void Cleanup()  
  2. {  
  3.     Dx::Release(VB);  
  4.     Dx::Release(IB);  
  5.     Dx::Release(font);  
  6. }  


运行结果



如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引