DirectX 遊戲編程之3D空間,頂點緩存及索引緩存

3D物體的模型表示

場景(scene)是物體或模型的的集合,所有物體都可以使用三角形網格逼近表示:


三角形(triangle)是構建物體模型的基本單元,也是基本圖元之一(Primitive,包括點和線段)

而構成三角形的則是頂點(vertex ),頂點在3D系統中描述一個點,三角形由三個點構成

基本圖元(Primitives)

3D空間圖形的基本組成元素就是圖元(Primitive),不僅僅是三角形,包括以下:

(以下圖形在z=0平面)

1點列表(Point Lists):由系列頂點組成,每個點都是獨立的,散列的

2線列表(Line Lists):每一組頂點構成一條獨立分隔的線段,通常用做3D網格,雨點,路標線等物體建模

3線條紋(Line Strips):類似於線列表,但是每兩條線又被一條線段連接,常用於wire-frame物體,如地形,草叢


4三角形列表(Triangle Lists):每三個頂點一組構成一個獨立的三角形

5三角形條紋(Triangle Strips):三角形間相互連接


6三角形扇面(Triangle Fans):所有三角形擁有一個共同頂點


頂點緩存與索引緩存

D3D使用靈活頂點格式(Flexible Vertex Format,FVF),定義一個頂點的位置及其他信息,包括顏色、法線等,通過組合不同頂點格式,以令我們可以自定義自己的頂點格式

#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
struct CUSTOMVERTEX
{
    FLOAT x, y, z, rhw;    // from the D3DFVF_XYZRHW flag
    DWORD color;    // from the D3DFVF_DIFFUSE flag
}

幾個重要的頂點格式:

D3DFVF_XYZ

指定x,y,z座標位置,同時它是Untransformed的,表明未經過頂點轉換到屏幕座標

D3DFVF_XYZRHW

指定xyz座標,不能與D3DFVF_XYZ共用,其是transformed,表明可以直接使用屏幕座標而不需要經過世界,取景,投影轉換等顯示在屏幕上。

D3DFVF_DIFFUSE

頂點包含32bit的漫反射顏色

D3DFVF_SPECULAR

包含32bit鏡面反射顏色

D3DFVF_NORMAL

包含法線向量(x,y,z)

D3DFVF_TEX0

-D3DFVF_TEX8

包含紋理座標(u,v)


一 頂點緩存的創建使用頂點緩存與索引緩存
HRESULT CreateVertexBuffer(
  UINT Length,
  DWORD Usage,
  DWORD FVF,
  D3DPOOL Pool,
  IDirect3DVertexBuffer9 **ppVertexBuffer,
  HANDLE *pSharedHandle
);

Length:爲緩存分配的字節數,爲頂點個數num*sizeof(Vertex)

Usage:緩存的附加屬性設置,可以爲以下值

D3DUSAGE_DYNAMIC 將緩存設定爲動態。

D3DUSAGE_WRITEONLY 緩存設定爲只寫

FVF:設置靈活頂點格式

Pool:內存池

ppVertexBuffer:頂點緩存的指針

pSharedHandle:保留,設爲0

// 三角形的頂點緩存創建
IDirect3DDevice9* Device = 0;
IDirect3DVertexBuffer9* Triangle = 0; // vertex buffer to store
                                      // our triangle data.
Device->CreateVertexBuffer(
		3 * sizeof(Vertex), // size in bytes
		D3DUSAGE_WRITEONLY, // flags,write only
		D3DFVF_XYZ,        // vertex format
		D3DPOOL_MANAGED,    // managed memory pool
		&Triangle,          // return create vertex buffer
		0);                 // not used - set to 0

索引緩存的創建:

HRESULT CreateIndexBuffer(
  UINT Length,
  DWORD Usage,
  D3DFORMAT Format,
  D3DPOOL Pool,
  IDirect3DIndexBuffer9 **ppIndexBuffer,
  HANDLE *pSharedHandle
);

二 訪問緩存內容

爲了訪問頂點緩存數據,先獲取緩存的內存指針

HRESULT IDirect3DVertexBuffer9::Lock(
  UINT OffsetToLock,
  UINT SizeToLock,
  VOID **ppbData,
  DWORD Flags
);

OffsetToLock:緩存開始到鎖定位置的偏移,單位爲字節bytes

SizeToLock:鎖定字節數。OffsetToLock,SizeToLock都爲0,表示鎖定全部緩存。

ppbData:指向鎖定開始位置的指針

Flags:鎖定方式

// 頂點數據格式
struct Vertex
{
	Vertex(){}
	Vertex(float x, float y, float z)
	{
		_x = x;	 _y = y;  _z = z;
	}
	float _x, _y, _z;
};
Vertex* vertices;
Triangle->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);
// Lock 與 Unlock 成對使用
Triangle->Unlock();

獲取頂點緩存或索引緩存信息的方法

HRESULT IDirect3DVertexBuffer9::GetDesc(
  D3DVERTEXBUFFER_DESC *pDesc
);

HRESULT IDirect3DIndexBuffer9::GetDesc(
  D3DINDEXBUFFER_DESC *pDesc
);

四 設置繪製狀態(rendering state)

HRESULT IDirect3DDevice9::SetRenderState(
  D3DRENDERSTATETYPE State,
  DWORD Value
);

我們設置繪製物體爲線框模式,原默認值爲:D3DFILL_SOLID

SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);

五 繪製設置

1數據流關聯,將頂點緩存設備數據流進行關聯

HRESULT IDirect3DDevice9::SetStreamSource(
  UINT StreamNumber,
  IDirect3DVertexBuffer9 *pStreamData,
  UINT OffsetInBytes,
  UINT Stride
);

StreamNumber:在使用多個數據流的情況下編號辨識。

pStreamData:IDirect3DVertexBuffer9頂點緩存指針。

OffsetInBytes:頂點數據開始的數據流偏移,以字節爲單位。

Stride:頂點緩存每個元素大小,字節爲單位。

SetStreamSource(0, Triangle, 0, sizeof(Vertex));

2設置繪製頂點格式。

HRESULT IDirect3DDevice9::SetFVF(
  DWORD FVF
);
例如:

SetFVF(D3DFVF_XYZ);

3如果是索引緩存,需要對繪製的索引進行設置,索引緩存與繪製數據流進行關聯。

HRESULT IDirect3DDevice9::SetIndices(
  IDirect3DIndexBuffer9 *pIndexData
);

六 頂點緩存或的繪製

以下爲頂點緩存繪製圖元函數

HRESULT IDirect3DDevice9::DrawPrimitive(
  D3DPRIMITIVETYPE PrimitiveType,
  UINT StartVertex,
  UINT PrimitiveCount
);

PrimitiveType:圖元類型,如繪製三角形時,使用D3DPT_TRIANGLELIST。

StartVertex:頂點數據流中開始繪製元素,以便可以部分繪製。

PrimitiveCount:繪製圖元數量。

如繪製一個三角形圖元,參考代碼中頂點位置:從頂點緩存的第一個元素開始繪製,繪製一個三角形圖元。

DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

頂點緩存的繪製:將頂點元素寫入緩存中,繪製是在緩存中根據索引取出頂點繪製。

繪製索引緩存圖元函數

HRESULT DrawIndexedPrimitive(
  D3DPRIMITIVETYPE Type,
  INT BaseVertexIndex,
  UINT MinIndex,
  UINT NumVertices,
  UINT StartIndex,
  UINT PrimitiveCount
);

Type:繪製圖元類型

BaseVertexIndex:頂點緩存中第幾個元素爲基位置,表示爲索引從該處開始,爲索引的最小值,如BaseVertexIndex:0,BaseVertexIndex+1:1,。

MinIndex:允許的最小索引值,一般爲0,這樣的索引列表爲0,1,2,3,4…

NumVertices:本次繪製的頂點數目,並非索引數目,矩形的NumVertices爲4,並非6。(矩形由兩個三角形基本圖元組成,共6個索引)

StartIndex:繪製索引的開始位置。

PrimitiveCount:繪製圖元總數。

 

使用頂點緩存如繪製一個正方體,頂點緩存內容:

struct Vertex
{
	Vertex(){}
	Vertex(float x, float y, float z)
	{
		_x = x;  _y = y;  _z = z;
	}
	float _x, _y, _z;
};
const DWORD Vertex::FVF = D3DFVF_XYZ;
IDirect3DDevice9* Device = 0;
IDirect3DVertexBuffer9* VB = 0;
IDirect3DIndexBuffer9*  IB = 0;
// 創建頂點緩存、索引緩存
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 of a unit cube
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);

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


// 繪製設置
Device->SetStreamSource(0, VB, 0, sizeof(Vertex));
Device->SetIndices(IB);
Device->SetFVF(Vertex::FVF);

// 繪製
Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);

各參數分別爲:以三角形爲圖元;頂點緩存中第一個元素爲索引開始;索引的最小值爲0,索引頂點的第一個元素爲索引0;正方體的頂點數目爲8個;從索引列表的第一個索引開始繪製;共12個三角形圖元。

注意:所有的繪製函數必須在 IDirect3DDevice9::BeginScene/ IDirect3DDevice9::EndScene 方法之間調用。


REF:

directxtutorial.com

《DIRECTX.9.0.3D遊戲開發編程基礎(Inroduction.to.3D.GAME.Programming.with.DirectX.9.0)》

發佈了49 篇原創文章 · 獲贊 6 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章