DirectX 3D编程入门教程(一)
发表于2017-09-12
本篇文章主要给大家介绍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开发环境已经实现了,可以直接去看。主要修改一下渲染的几个函数。
- #include "dxutility.h"
- #include
- #include
- //
- // Globals
- //
- IDirect3DDevice9* Device = 0;
- D3DXMATRIX World;
- IDirect3DVertexBuffer9 * VB = 0;
- const int Width = 800;
- const int Height = 600;
- struct Vertex{
- Vertex(){};
- Vertex(float _x, float _y, float _z)
- {
- x = _x;
- y = _y;
- z = _z;
- }
- float x, y, z;
- static const DWORD FVF;
- };
- const DWORD Vertex::FVF = D3DFVF_XYZ;
- //
- // Framework Functions
- //
- bool Setup()
- {
- Device->CreateVertexBuffer(
- 3 * sizeof(Vertex),
- D3DUSAGE_WRITEONLY,
- Vertex::FVF,
- D3DPOOL_MANAGED,
- &VB,
- 0);
- Vertex* vertices;
- VB->Lock(0, 0, (void**)&vertices, 0);
- vertices[0] = Vertex(-1.0f, 0.0f, 2.0f);
- vertices[1] = Vertex(0.0f, 1.0f, 2.0f);
- vertices[2] = Vertex(1.0f, 0.0f, 2.0f);
- VB->Unlock();
- D3DXMATRIX proj;
- D3DXMatrixPerspectiveFovLH(
- &proj, // result
- D3DX_PI * 0.5f, // 90 - degrees
- (float)Width / (float)Height, // aspect ratio
- 1.0f, // near plane
- 1000.0f); // far plane
- Device->SetTransform(D3DTS_PROJECTION, &proj);
- Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
- return true;
- }
- void Cleanup()
- {
- Dx::Release
(VB); - }
- bool Display(float timeDelta)
- {
- if (Device) // Only use Device methods if we have a valid device.
- {
- Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
- Device->BeginScene();
- Device->SetStreamSource(0, VB, 0, sizeof(Vertex));
- Device->SetFVF(Vertex::FVF);
- // Draw one triangle.
- Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
- Device->EndScene();
- Device->Present(0, 0, 0, 0);
- }
- return true;
- }
- //
- // WndProc
- //
- LRESULT CALLBACK Dx::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 (!Dx::InitDx(hinstance,
- Width, Height, true, D3DDEVTYPE_HAL, &Device))
- {
- ::MessageBox(0, "InitD3D() - FAILED", 0, 0);
- return 0;
- }
- if (!Setup())
- {
- ::MessageBox(0, "Setup() - FAILED", 0, 0);
- return 0;
- }
- Dx::EnterMsgLoop(Display);
- Cleanup();
- Device->Release();
- return 0;
- }
最终效果
给三角形加上颜色
数据结构定义
- struct ColorVertex{
- ColorVertex(float _x, float _y, float _z, D3DCOLOR c)
- {
- x = _x;
- y = _y;
- z = _z;
- color = c;
- }
- float x, y, z;
- D3DCOLOR color;
- static const DWORD FVF;
- };
- const DWORD ColorVertex::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;
创建Buffer
- Device->CreateVertexBuffer(
- 3 * sizeof(ColorVertex),
- D3DUSAGE_WRITEONLY,
- ColorVertex::FVF,
- D3DPOOL_MANAGED,
- &VB,
- 0);
- ColorVertex *v;
- VB->Lock(0, 0, (void**)&v, 0);
- v[0] = ColorVertex(-1.0f, 0.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0));
- v[1] = ColorVertex(0.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(0, 255, 0));
- v[2] = ColorVertex(1.0f, 0.0f, 2.0f, D3DCOLOR_XRGB(0, 0, 255));
- VB->Unlock();
在绘制函数中设置使用Ground插值进行三角形绘制
- bool Display(float timeDelta)
- {
- if (Device) // Only use Device methods if we have a valid device.
- {
- std::cout << "Display" << std::endl;
- Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
- Device->BeginScene();
- Device->SetStreamSource(0, VB, 0, sizeof(ColorVertex));
- Device->SetFVF(ColorVertex::FVF);
- Device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
- Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
- Device->EndScene();
- Device->Present(0, 0, 0, 0);
- }
- return true;
- }
渲染结果
绘制一个旋转的正方体
生成Vertex Buffer和Index Buffer
- Device->CreateVertexBuffer(
- 8 * sizeof(ColorVertex),
- D3DUSAGE_WRITEONLY,
- ColorVertex::FVF,
- D3DPOOL_MANAGED,
- &VB,
- 0);
- Device->CreateIndexBuffer(
- 36 * sizeof(WORD),
- D3DUSAGE_WRITEONLY,
- D3DFMT_INDEX16,
- D3DPOOL_MANAGED,
- &IB,
- 0);
- ColorVertex *v;
- VB->Lock(0, 0, (void**)&v, 0);
- v[0] = ColorVertex(-1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(255, 0, 0));
- v[1] = ColorVertex(-1.0f, 1.0f, -1.0f, D3DCOLOR_XRGB(0, 255, 0));
- v[2] = ColorVertex(1.0f, 1.0f, -1.0f, D3DCOLOR_XRGB(0, 0, 255));
- v[3] = ColorVertex(1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(255, 255, 0));
- v[4] = ColorVertex(-1.0f, -1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0));
- v[5] = ColorVertex(-1.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255));
- v[6] = ColorVertex(1.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 255));
- v[7] = ColorVertex(1.0f, -1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0));
- VB->Unlock();
- WORD* indices = 0;
- IB->Lock(0, 0, (void**)&indices, 0);
- // front side
- indices[0] = 0; indices[1] = 1; indices[2] = 2;
- indices[3] = 0; indices[4] = 2; indices[5] = 3;
- // back side
- indices[6] = 4; indices[7] = 6; indices[8] = 5;
- indices[9] = 4; indices[10] = 7; indices[11] = 6;
- // left side
- indices[12] = 4; indices[13] = 5; indices[14] = 1;
- indices[15] = 4; indices[16] = 1; indices[17] = 0;
- // right side
- indices[18] = 3; indices[19] = 2; indices[20] = 6;
- indices[21] = 3; indices[22] = 6; indices[23] = 7;
- // top
- indices[24] = 1; indices[25] = 5; indices[26] = 6;
- indices[27] = 1; indices[28] = 6; indices[29] = 2;
- // bottom
- indices[30] = 4; indices[31] = 0; indices[32] = 3;
- indices[33] = 4; indices[34] = 3; indices[35] = 7;
- IB->Unlock();
绘制函数,让正方体旋转起来
- // spin the cube:
- //
- D3DXMATRIX Rx, Ry;
- // rotate 45 degrees on x-axis
- D3DXMatrixRotationX(&Rx, 3.14f / 4.0f);
- // incremement y-rotation angle each frame
- static float y = 0.0f;
- D3DXMatrixRotationY(&Ry, y);
- y = timeDelta;
- // reset angle to zero when angle reaches 2*PI
- if (y >= 6.28f)
- y = 0.0f;
- // combine x- and y-axis rotation transformations.
- D3DXMATRIX p = Rx * Ry;
- Device->SetTransform(D3DTS_WORLD, &p);
- Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
- Device->BeginScene();
- Device->SetStreamSource(0, VB, 0, sizeof(ColorVertex));
- Device->SetIndices(IB);
- Device->SetFVF(ColorVertex::FVF);
- Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);
- Device->EndScene();
- Device->Present(0, 0, 0, 0);
在屏幕上显示FPS信息
首先初始化文字
- D3DXFONT_DESC d3dFont;
- memset(&d3dFont, 0, sizeof(d3dFont));
- d3dFont.Height = 25; // in logical units
- d3dFont.Width = 12; // in logical units
- d3dFont.Weight = 500;// boldness, range 0(light) - 1000(bold)
- d3dFont.Italic = FALSE;
- d3dFont.CharSet = DEFAULT_CHARSET;
- strcpy_s(d3dFont.FaceName, "Times New Roman");
- if (FAILED(D3DXCreateFontIndirect(Device, &d3dFont, &font)))
- {
- ::MessageBox(0, "D3DXCreateFontIndirect() - FAILED", 0, 0);
- ::PostQuitMessage(0);
- }
声明几个变量
- ID3DXFont* font = 0;
- DWORD FrameCnt = 0;
- float TimeElapsed = 0;
- float FPS = 0;
- char FPSString[16];
FPS的计算
- FrameCnt ;
- TimeElapsed = timeDelta;
- if (TimeElapsed >= 1.0f)
- {
- FPS = (float)FrameCnt / TimeElapsed;
- sprintf_s(FPSString, "FPS:%f", FPS);
- FPSString[15] = '\0'; // mark end of string
- TimeElapsed = 0.0f;
- FrameCnt = 0;
- }
文字的渲染
- Device->BeginScene();
- RECT rect = { 0, 0, Width, Height };
- font->DrawText(
- m_pSprite,
- FPSString,
- -1, // size of string or -1 indicates null terminating string
- &rect, // rectangle text is to be formatted to in windows coords
- DT_TOP | DT_LEFT, // draw in the top left corner of the viewport
- 0xff000000); // black text
- Device->EndScene();
记住最后要Clear掉COM对象
- void Cleanup()
- {
- Dx::Release
(VB); - Dx::Release
(IB); - Dx::Release
(font); - }
运行结果