在螢幕繪製一個旋轉的線框立方體(使用頂點快取和索引快取)
阿新 • • 發佈:2018-11-22
首先裡面還是有兩個基本的檔案:d3dUtility.h以及d3dUtility.cpp
裡面的主要內容就是實現Direct3D的初始化,以及模板函式的的實現,和訊息迴圈函式的宣告,回撥函式的宣告。
具體的解釋在部落格:在螢幕繪製一個三角形以及Direct3D初始化例程中有詳細的解釋,這裡就不在過多的重複。
我們主要來看主函式檔案Cube.cpp裡面是怎麼實現,我們在程式碼中詳細的講解,下面是cube.cpp內容:
//包含標頭檔案 #include "d3dUtility.h" //定義一個裝置型別的指標,準備指向裝置 IDirect3DDevice9* Device = 0; //定義兩個資料,用來規定視窗的大小 const int Width = 640; const int Height = 480; //定義兩個指標,一個準備指向頂點快取(VertexBuffer),一個準備指向索引快取(IndexBuffer) IDirect3DVertexBuffer9* VB = 0; IDirect3DIndexBuffer9* IB = 0; //定義一個頂點,裡面有x,y,z座標 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; //資源的分配 bool Setup() { //將我們剛才建立的頂點快取VP進行例項化 Device->CreateVertexBuffer( 8 * sizeof(Vertex), //開闢可以存放8個頂點的快取用來給VP指 D3DUSAGE_WRITEONLY, //頂點快取的使用格式,是幾個列舉型別,這個列舉型別表示建立的頂點快取只能寫 Vertex::FVF, //將頂點的靈活頂點格式傳進來 D3DPOOL_MANAGED, //記憶體池得型別 &VB, //定義的頂點快取的指標 0); //不使用,文件裡面說是給Window Vista使用 //將我們剛才建立的索引快取進行IP例項化 Device->CreateIndexBuffer( 36 * sizeof(WORD), //開闢可以存放36個索引的空間給IP指 D3DUSAGE_WRITEONLY, //索引快取的屬性,同上面的頂點快取的對應引數 D3DFMT_INDEX16, //索引快取的位數,32位和16位,32位有些硬體不支援 D3DPOOL_MANAGED, //記憶體池的型別 &IB, //定義的指向索引快取的指標 0); //不使用,文件裡面說是給Window Vista使用 //用頂點的結構定義一個指標,用來 Vertex* vertices; //對方問的頂點進行上鎖 VB->Lock(0, 0, (void**)&vertices, 0); //對頂點進行賦值,正方形有8個點 vertices[0] = Vertex(-1.0f, -1.0f, -1.0f); vertices[1] = Vertex(-1.0f, 1.0f, -1.0f); vertices[2] = Vertex(1.0f, 1.0f, -1.0f); vertices[3] = Vertex(1.0f, -1.0f, -1.0f); vertices[4] = Vertex(-1.0f, -1.0f, 1.0f); vertices[5] = Vertex(-1.0f, 1.0f, 1.0f); vertices[6] = Vertex(1.0f, 1.0f, 1.0f); vertices[7] = Vertex(1.0f, -1.0f, 1.0f); //解鎖 VB->Unlock(); // 定義多維資料集的三角形 WORD* indices = 0; IB->Lock(0, 0, (void**)&indices, 0); //裡面存放的是vertices數組裡面的索引, /* 前面要繪製兩個三角形, 第一個三角形,索引快取0,1,2裡面分別存放的是頂點vertices[0],vertices[1],vertices[2] 第二個三角形,索引快取3,4,5裡面分別存放的是頂點vertices[0],vertices[2],vertices[3] 索引快取裡面存放的是頂點快取裡面頂點的索引 後面同理 */ indices[0] = 0; indices[1] = 1; indices[2] = 2; indices[3] = 0; indices[4] = 2; indices[5] = 3; // 後面 indices[6] = 4; indices[7] = 6; indices[8] = 5; indices[9] = 4; indices[10] = 7; indices[11] = 6; // 左面 indices[12] = 4; indices[13] = 5; indices[14] = 1; indices[15] = 4; indices[16] = 1; indices[17] = 0; // 右面 indices[18] = 3; indices[19] = 2; indices[20] = 6; indices[21] = 3; indices[22] = 6; indices[23] = 7; // 上面 indices[24] = 1; indices[25] = 5; indices[26] = 6; indices[27] = 1; indices[28] = 6; indices[29] = 2; // 下面 indices[30] = 4; indices[31] = 0; indices[32] = 3; indices[33] = 4; indices[34] = 3; indices[35] = 7; IB->Unlock(); //攝影機在世界座標中的位置 D3DXVECTOR3 position(0.0f, 0.0f, -5.0f); //被觀察的點在世界座標的位置 D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); //世界座標系中向上方向的向量 D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); D3DXMATRIX V; //通過這個介面獲取世界矩陣 D3DXMatrixLookAtLH(&V, &position, &target, &up); //設施世界矩陣 Device->SetTransform(D3DTS_VIEW, &V); //用於接收投影矩陣的矩陣 D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH( &proj, D3DX_PI * 0.5f, // 視域體的視域角:90度 (float)Width / (float)Height,//縱橫比:為了減少正方形矩陣對映到矩形螢幕之後的畸變 1.0f, //到近平面的距離 1000.0f); //到原平面的距離 //設施投影矩陣 Device->SetTransform(D3DTS_PROJECTION, &proj); //設定繪製狀態 Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); return true; } void Cleanup() { d3d::Release<IDirect3DVertexBuffer9*>(VB); d3d::Release<IDirect3DIndexBuffer9*>(IB); } bool Display(float timeDelta) { if (Device) { //定義兩個矩陣 D3DXMATRIX Rx, Ry; // 得到一個矩陣Rx:乘這個矩陣就相當於:在X軸上旋轉45度 D3DXMatrixRotationX(&Rx, 3.14f / 4.0f); // 每一幀增加y的旋轉角度 static float y = 0.0f; //得到一個矩陣Ry:乘以這個矩陣就相當於在Y軸旋轉y度,y是一直在變化的 D3DXMatrixRotationY(&Ry, y); y += timeDelta; //如果角度大於360度,也就是轉了一圈,就將y軸的旋轉角度重置為0 if (y >= 6.28f) y = 0.0f; // 結合矩陣Rx以及Ry, 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(Vertex)); //設定索引快取 Device->SetIndices(IB); //設定靈活頂點格式 Device->SetFVF(Vertex::FVF); //使用介面畫出來 Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12); Device->EndScene(); //在裝置擁有的後臺緩衝區中顯示下一個內容 Device->Present(0, 0, 0, 0); } return true; } //回撥函式 //當視窗收到訊息的時候應該做出什麼動作 //這個函式功能就是:按鍵“ESC”,視窗退出 LRESULT CALLBACK d3d::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); } // int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd) { //Direct3d初始化 if (!d3d::InitD3D(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; } //呼叫Display畫出來 d3d::EnterMsgLoop(Display); Cleanup(); Device->Release(); return 0; }