两天学会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 <windows.h> #include <iostream> // // 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<IDirect3DVertexBuffer9*>(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<IDirect3DVertexBuffer9*>(VB); Dx::Release<IDirect3DIndexBuffer9*>(IB); Dx::Release<ID3DXFont*>(font); }
执行结果
參考
Introduction to 3D Game Programming with DirectX® 9.0