看完二、三章,新的概念太多了,而且寫過第一個例子之後回頭再看第一章才能真正理解許多概念到底是什麼意思,所以正確的方法應該是先粗略地讀一下第一章,看完二三章再回頭看第一章。這章概念是真的多,乾脆直接把這些概念啊,函數啊放在實例里來說算了,方便理解。


先把DirectX繪圖的大概思路捋一遍:

1.設置全局變數:包括 IDirect3DDevice9的實例*Device、屏幕的長(int width)和高(int height)、 是否窗口化(bool windowed)、頂點緩存的指針(IDirect3DVertexBuffer9 *vb)、引索緩存的指針(IDirect3DIndexBuffer9 *ib)等等,暫時用到這麼多。

2.設置靈活頂點格式(P60):本質上定義一個Vertex的結構體,可以自己寫成員類型,但注意還要定義一個FVF標記來描述頂點格式,可以在結構體外面或裡面用DWORD定義,可以宏定義,可以用的時候直接寫。(有很多種,用的時候翻文檔吧)

3.setup()函數在本例中的功能:

(1)頂點緩存分配空間Device->CreateVertexBuffer():

HRESULT CreateVertexBuffer(
UINT Length, /*分配頂點的位元組數 (X * sizeof(Vertex)) */
DWORD Usage, /*附加屬性P74*/
DWORD FVF, /*靈活頂點格式*/
D3DPOOL Pool, /*內存池 每種特性不一樣 P42*/
IDirect3DVertexBuffer9 **ppVertexBuffer, /*頂點緩存的指針*/
HANDLE *pSharedHandle /*一般為0*/
);

(2)引索緩存分配空間Device->CreateIndexBuffer():

HRESULT CreateIndexBuffer(
UINT Length, /*分配頂點的位元組數 (X * sizeof(Vertex)) */
DWORD Usage, /*附加屬性P74*/
D3DFORMAT Format, /*引索格式 翻文檔*/
D3DPOOL Pool, /*內存池 每種特性不一樣 P42*/
IDirect3DIndexBuffer9 **ppIndexBuffer, /*引索緩存的指針*/
HANDLE *pSharedHandle /*一般為0*/
);

(3)為頂點緩存賦值:

流程:創建一個頂點指針(Vertex *vertices)--->鎖定緩存區(vb->Lock(0, 0, (void**)&vertices, 0);)--->用vertices[]數組為頂點緩存賦值--->解鎖緩存區(vb->Unlock();)

(4)為引索緩存賦值:

流程:創建一個引索指針(WORD *indices)--->鎖定緩存區(ib->Lock(0, 0, (void**)&indices, 0);)--->用indices[]數組為頂點緩存賦值--->解鎖緩存區(ib->Unlock();)

4. Display()函數在本例中的功能(實例中有補充的注釋):

  • 設定觀察矩陣、投影矩陣。
  • 世界坐標系中的矩陣變換:物體的平移、旋轉、縮放...
  • 觀察坐標系中的矩陣變換:攝像機的平移、旋轉、縮放...
  • 設定投影矩陣
  • 設定繪製狀態(繪製三角形、點、線……)
  • 指定頂點緩存:Device->SetStreamSource();
  • 指定引索緩存:Device->SetIndices(ib);
  • 設置靈活頂點格式:Device->SetFVF(Vertex::FVF);
  • Device->BeginScene();
  • 進行繪製:Device->DrawIndexedPrimitive();
  • Device->EndScene();
  • Device->Present(0,0,0,0);

5.Cleanup()函數在本例中的功能:

  • 釋放頂點緩存:d3d::Release<IDirect3DVertexBuffer9*>(vb);
  • 釋放引索緩存:d3d::Release<IDirect3DIndexBuffer9*>(ib);

源代碼commonFunc.h

#pragma once
#ifndef COMMONFUNC_H
#define COMMONFUNC_H

#include "d3dUtility.h"
IDirect3DDevice9 *Device = 0;
extern const int width = 1800;
extern const int height = 900;
extern bool windowed = true;

IDirect3DVertexBuffer9 *vb = 0; //頂點緩存
IDirect3DIndexBuffer9 *ib = 0; //引索緩存

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() {
Device->CreateVertexBuffer(8 * sizeof(Vertex), D3DUSAGE_WRITEONLY, Vertex::FVF, D3DPOOL_MANAGED, &vb, 0);
Device->CreateIndexBuffer(36 * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &ib, 0);
Vertex *vertices; //為獲取頂點緩存內容而創建的指針
vb->Lock(0, 0, (void**)&vertices, 0); //鎖定頂點緩存

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);

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();

return true;
}

void Cleanup() {
d3d::Release<IDirect3DVertexBuffer9*>(vb);
d3d::Release<IDirect3DIndexBuffer9*>(ib);

}

bool Display(float timeDelta) {
if (Device)
{
D3DXVECTOR3 position(0.0f, 0.0f, -3.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, 3.1415926f*0.5f, (float)width / (float)height, 1.0f, 100.0f);
//計算投影矩陣 參數:[1]輸出矩陣的地址 [2]視角廣度(弧度制) [3]橫縱比 [4]最近能看見的距離 [5]最遠能看見的距離
Device->SetTransform(D3DTS_PROJECTION, &proj);
//設定投影矩陣
Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
//設定繪製狀態 參數 :[1]要改變的某類繪製狀態 [2]將該類繪製狀態改為...狀態

D3DXMATRIX Rx, Ry;
D3DXMatrixRotationX(&Rx, 3.14f / 4.0f);
//繞x軸旋轉45°

static float y = 0.0f;
D3DXMatrixRotationY(&Ry, y);
//繞y軸旋轉timeDelta°
y += timeDelta;

if (y >= 6.28f)
y = 0.0f;

D3DXMATRIX p = Rx * Ry;
Device->SetTransform(D3DTS_WORLD, &p);
//改變世界坐標系

Device->SetStreamSource(0, vb, 0, sizeof(Vertex));
//指定數據輸入源 參數[1]標識頂點緩存 [2]頂點緩存的指針 [3]偏移量(要使用要先檢查D3DDEVCAPS2_STREAMOFFSET標記) [4]頂點元素大小(位元組)
Device->SetIndices(ib);
//設定引索緩存
Device->SetFVF(Vertex::FVF);
//設置靈活頂點格式

Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, RGB(0, 255, 255), 1.0f, 0);
//清空後台緩存把它變為某一種顏色並將其提供給前台緩存
Device->BeginScene();
Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);
//進行繪製 參數[1]繪製圖元類型 [2]引索的基數(P80) [3]最小引索值 [4]引用的頂點數 [5]讀取起始點的元素的引索 [6]要繪製的圖元總數
Device->EndScene();
Device->Present(0,0,0,0);
}
return true;
}

#endif

效果:

註:該程序中立方體的旋轉是通過旋轉世界坐標,即整個世界都會旋轉,單獨旋轉某個物體的方法還不知道。

推薦閱讀:

相关文章