Directx11學習筆記【十五】 基本幾何體的繪制


本文由zhangbaochong原創,轉載請注明出處http://www.cnblogs.com/zhangbaochong/p/5573970.html

  前面實現簡單地形的教程,我們只是繪制了一個網格,這一次我們來學習一下幾種基本幾何體的繪制,包括平面網格、立方體、圓柱和球體等。

原來在GeometryGenerator類中只給出了CreateGrid一個方法來繪制網格,現在讓我們添加其他方法繪制一些幾何體。

  為了方便繪制幾何體方法的調用,GeometryGenerator類我們使用了單例模式。很簡單,將構造函數設為private,添加一個GetInstance函數如下:

//單例模式
    static GeometryGenerator* GetInstance()
    {
        static GeometryGenerator instance;
        return &instance;
    }

  這只是實現單例模式的一種方法,還有幾種實現單例模式的方法就不一一說明了。

1.基本幾何體繪制方法 

  下面介紹幾種常見幾何體的繪制方法(代碼均參考dx11龍書)。

1.1網格

  網格可以說是最常見同時也是最重要的,像實現地形水面等都離不開網格。生成一個網格首先要給出網格的寬和高,以及在寬和高上划分的格子數。

看龍書中給出的一張圖片就明白了:

由此,頂點的坐標就很容易生成了。

 

頂點索引的計算關鍵是推導出一個用於求構成第i行,第j列的頂點處右下方兩個三角形的頂點索引的通用公式。

對頂點緩存中的任意一點A,如果該點位於地形中的第i行、第j列的話,那么該點在頂點緩存中所對應的位置應該就是i*m+j(m為每行的頂點數)。如果A點在索引緩存中的位置為k的話,那么A點為起始點構成的三角形ABC中,B、C頂點在頂點緩存中的位置就為(i+1)x m+j和i x m+(j+1)。且B點索引值為k+1,C點索引值為k+2.這樣。這樣,公式就可以推導為如下:

三角形ABC=【i*每行頂點數+j,i*每行頂點數+(j+1),(i+1)*行頂點數+j】

三角形CBD=【(i+1)*每行頂點數+j,i*每行頂點數+(j+1),(i+1)*行頂點數+(j+1)】

 

 1 void GeometryGenerator::CreateGrid(float width, float height, UINT m, UINT n, MeshData &mesh)
 2 {
 3     mesh.vertices.clear();
 4     mesh.indices.clear();
 5     //每行頂點數、每列頂點數
 6     UINT nVertsRow = m + 1;
 7     UINT nVertsCol = n + 1;
 8     //起始x、z坐標
 9     float oX = -width * 0.5f;
10     float oZ = height * 0.5f;
11     //每一格坐標變化
12     float dx = width / m;
13     float dz = height / n;
14 
15     //頂點總數量:nVertsRow * nVertsCol
16     mesh.vertices.resize(nVertsRow * nVertsCol);
17 
18     //逐個添加頂點
19     for (UINT i = 0; i < nVertsCol; ++i)
20     {
21         float tmpZ = oZ - dz * i;
22         for (UINT j = 0; j < nVertsRow; ++j)
23         {
24             UINT index = nVertsRow * i + j;
25             mesh.vertices[index].pos.x = oX + dx * j;
26             mesh.vertices[index].pos.y = 0.f;
27             mesh.vertices[index].pos.z = tmpZ;
28 
29             mesh.vertices[index].normal = XMFLOAT3(0.f, 1.f, 0.f);
30             mesh.vertices[index].tangent = XMFLOAT3(1.f, 0.f, 0.f);
31 
32             mesh.vertices[index].tex = XMFLOAT2(dx*i, dx*j);
33         }
34     }
35 
36     //總格子數量:m * n
37     //因此總索引數量: 6 * m * n
38     UINT nIndices = m * n * 6;
39     mesh.indices.resize(nIndices);
40     UINT tmp = 0;
41     for (UINT i = 0; i < n; ++i)
42     {
43         for (UINT j = 0; j < m; ++j)
44         {
45             mesh.indices[tmp] = i * nVertsRow + j;
46             mesh.indices[tmp + 1] = i * nVertsRow + j + 1;
47             mesh.indices[tmp + 2] = (i + 1) * nVertsRow + j;
48             mesh.indices[tmp + 3] = i * nVertsRow + j + 1;
49             mesh.indices[tmp + 4] = (i + 1) * nVertsRow + j + 1;
50             mesh.indices[tmp + 5] = (i + 1) * nVertsRow + j;
51 
52             tmp += 6;
53         }
54     }
55 }

 

1.2立方體

  立方體的繪制就很簡單了,一個立方體只需要提供三維方向上的長度。有一點與之前繪制彩色立方體時不一樣的是,我們這里創建立方體用到24個頂點(每個面4個),而之前彩色立方體只用到了8個頂點(每個頂點被3個面共享)。這是因為在后面學習過程中我們需要頂點的法線坐標,而一個頂點相對於其連接的3個面來說,法線完全不同,因此無法共享頂點。

  1 void GeometryGenerator::CreateBox(float width, float height, float depth, MeshData &mesh)
  2 {
  3     mesh.vertices.clear();
  4     mesh.indices.clear();
  5 
  6     //一共24個頂點(每面4個)
  7     mesh.vertices.resize(24);
  8     //一共36個索引(每面6個)
  9     mesh.indices.resize(36);
 10 
 11     float halfW = width * 0.5f;
 12     float halfH = height * 0.5f;
 13     float halfD = depth * 0.5f;
 14 
 15     //眼睛面向z軸正方向
 16     //構建頂點
 17     //前面
 18     mesh.vertices[0].pos = XMFLOAT3(-halfW, -halfH, -halfD);
 19     mesh.vertices[0].normal = XMFLOAT3(0.f, 0.f, -1.f);
 20     mesh.vertices[0].tangent = XMFLOAT3(1.f, 0.f, 0.f);
 21     mesh.vertices[0].tex = XMFLOAT2(0.f, 1.f);
 22     mesh.vertices[1].pos = XMFLOAT3(-halfW, halfH, -halfD);
 23     mesh.vertices[1].normal = XMFLOAT3(0.f, 0.f, -1.f);
 24     mesh.vertices[1].tangent = XMFLOAT3(1.f, 0.f, 0.f);
 25     mesh.vertices[1].tex = XMFLOAT2(0.f, 0.f);
 26     mesh.vertices[2].pos = XMFLOAT3(halfW, halfH, -halfD);
 27     mesh.vertices[2].normal = XMFLOAT3(0.f, 0.f, -1.f);
 28     mesh.vertices[2].tangent = XMFLOAT3(1.f, 0.f, 0.f);
 29     mesh.vertices[2].tex = XMFLOAT2(1.f, 0.f);
 30     mesh.vertices[3].pos = XMFLOAT3(halfW, -halfH, -halfD);
 31     mesh.vertices[3].normal = XMFLOAT3(0.f, 0.f, -1.f);
 32     mesh.vertices[3].tangent = XMFLOAT3(1.f, 0.f, 0.f);
 33     mesh.vertices[3].tex = XMFLOAT2(1.f, 1.f);
 34     //左側面
 35     mesh.vertices[4].pos = XMFLOAT3(-halfW, -halfH, halfD);
 36     mesh.vertices[4].normal = XMFLOAT3(-1.f, 0.f, 0.f);
 37     mesh.vertices[4].tangent = XMFLOAT3(0.f, 0.f, -1.f);
 38     mesh.vertices[4].tex = XMFLOAT2(0.f, 1.f);
 39     mesh.vertices[5].pos = XMFLOAT3(-halfW, halfH, halfD);
 40     mesh.vertices[5].normal = XMFLOAT3(-1.f, 0.f, 0.f);
 41     mesh.vertices[5].tangent = XMFLOAT3(0.f, 0.f, -1.f);
 42     mesh.vertices[5].tex = XMFLOAT2(0.f, 0.f);
 43     mesh.vertices[6].pos = XMFLOAT3(-halfW, halfH, -halfD);
 44     mesh.vertices[6].normal = XMFLOAT3(-1.f, 0.f, 0.f);
 45     mesh.vertices[6].tangent = XMFLOAT3(0.f, 0.f, -1.f);
 46     mesh.vertices[6].tex = XMFLOAT2(1.f, 0.f);
 47     mesh.vertices[7].pos = XMFLOAT3(-halfW, -halfH, -halfD);
 48     mesh.vertices[7].normal = XMFLOAT3(-1.f, 0.f, 0.f);
 49     mesh.vertices[7].tangent = XMFLOAT3(0.f, 0.f, -1.f);
 50     mesh.vertices[7].tex = XMFLOAT2(1.f, 1.f);
 51     //背面
 52     mesh.vertices[8].pos = XMFLOAT3(halfW, -halfH, halfD);
 53     mesh.vertices[8].normal = XMFLOAT3(0.f, 0.f, 1.f);
 54     mesh.vertices[8].tangent = XMFLOAT3(-1.f, 0.f, 0.f);
 55     mesh.vertices[8].tex = XMFLOAT2(0.f, 1.f);
 56     mesh.vertices[9].pos = XMFLOAT3(halfW, halfH, halfD);
 57     mesh.vertices[9].normal = XMFLOAT3(0.f, 0.f, 1.f);
 58     mesh.vertices[9].tangent = XMFLOAT3(-1.f, 0.f, 0.f);
 59     mesh.vertices[9].tex = XMFLOAT2(0.f, 0.f);
 60     mesh.vertices[10].pos = XMFLOAT3(-halfW, halfH, halfD);
 61     mesh.vertices[10].normal = XMFLOAT3(0.f, 0.f, 1.f);
 62     mesh.vertices[10].tangent = XMFLOAT3(-1.f, 0.f, 0.f);
 63     mesh.vertices[10].tex = XMFLOAT2(1.f, 0.f);
 64     mesh.vertices[11].pos = XMFLOAT3(-halfW, -halfH, halfD);
 65     mesh.vertices[11].normal = XMFLOAT3(0.f, 0.f, 1.f);
 66     mesh.vertices[11].tangent = XMFLOAT3(-1.f, 0.f, 0.f);
 67     mesh.vertices[11].tex = XMFLOAT2(1.f, 1.f);
 68     //右側面
 69     mesh.vertices[12].pos = XMFLOAT3(halfW, -halfH, -halfD);
 70     mesh.vertices[12].normal = XMFLOAT3(1.f, 0.f, 0.f);
 71     mesh.vertices[12].tangent = XMFLOAT3(0.f, 0.f, 1.f);
 72     mesh.vertices[12].tex = XMFLOAT2(0.f, 1.f);
 73     mesh.vertices[13].pos = XMFLOAT3(halfW, halfH, -halfD);
 74     mesh.vertices[13].normal = XMFLOAT3(1.f, 0.f, 0.f);
 75     mesh.vertices[13].tangent = XMFLOAT3(0.f, 0.f, 1.f);
 76     mesh.vertices[13].tex = XMFLOAT2(0.f, 0.f);
 77     mesh.vertices[14].pos = XMFLOAT3(halfW, halfH, halfD);
 78     mesh.vertices[14].normal = XMFLOAT3(1.f, 0.f, 0.f);
 79     mesh.vertices[14].tangent = XMFLOAT3(0.f, 0.f, 1.f);
 80     mesh.vertices[14].tex = XMFLOAT2(1.f, 0.f);
 81     mesh.vertices[15].pos = XMFLOAT3(halfW, -halfH, halfD);
 82     mesh.vertices[15].normal = XMFLOAT3(1.f, 0.f, 0.f);
 83     mesh.vertices[15].tangent = XMFLOAT3(0.f, 0.f, 1.f);
 84     mesh.vertices[15].tex = XMFLOAT2(1.f, 1.f);
 85     //上面
 86     mesh.vertices[16].pos = XMFLOAT3(-halfW, halfH, -halfD);
 87     mesh.vertices[16].normal = XMFLOAT3(0.f, 1.f, 0.f);
 88     mesh.vertices[16].tangent = XMFLOAT3(1.f, 0.f, 0.f);
 89     mesh.vertices[16].tex = XMFLOAT2(0.f, 1.f);
 90     mesh.vertices[17].pos = XMFLOAT3(-halfW, halfH, halfD);
 91     mesh.vertices[17].normal = XMFLOAT3(0.f, 1.f, 0.f);
 92     mesh.vertices[17].tangent = XMFLOAT3(1.f, 0.f, 0.f);
 93     mesh.vertices[17].tex = XMFLOAT2(0.f, 0.f);
 94     mesh.vertices[18].pos = XMFLOAT3(halfW, halfH, halfD);
 95     mesh.vertices[18].normal = XMFLOAT3(0.f, 1.f, 0.f);
 96     mesh.vertices[18].tangent = XMFLOAT3(1.f, 0.f, 0.f);
 97     mesh.vertices[18].tex = XMFLOAT2(1.f, 0.f);
 98     mesh.vertices[19].pos = XMFLOAT3(halfW, halfH, -halfD);
 99     mesh.vertices[19].normal = XMFLOAT3(0.f, 1.f, 0.f);
100     mesh.vertices[19].tangent = XMFLOAT3(1.f, 0.f, 0.f);
101     mesh.vertices[19].tex = XMFLOAT2(1.f, 1.f);
102     //底面
103     mesh.vertices[20].pos = XMFLOAT3(-halfW, -halfH, halfD);
104     mesh.vertices[20].normal = XMFLOAT3(0.f, -1.f, 0.f);
105     mesh.vertices[20].tangent = XMFLOAT3(1.f, 0.f, 0.f);
106     mesh.vertices[20].tex = XMFLOAT2(0.f, 1.f);
107     mesh.vertices[21].pos = XMFLOAT3(-halfW, -halfH, -halfD);
108     mesh.vertices[21].normal = XMFLOAT3(0.f, -1.f, 0.f);
109     mesh.vertices[21].tangent = XMFLOAT3(1.f, 0.f, 0.f);
110     mesh.vertices[21].tex = XMFLOAT2(0.f, 0.f);
111     mesh.vertices[22].pos = XMFLOAT3(halfW, -halfH, -halfD);
112     mesh.vertices[22].normal = XMFLOAT3(0.f, -1.f, 0.f);
113     mesh.vertices[22].tangent = XMFLOAT3(1.f, 0.f, 0.f);
114     mesh.vertices[22].tex = XMFLOAT2(1.f, 0.f);
115     mesh.vertices[23].pos = XMFLOAT3(halfW, -halfH, halfD);
116     mesh.vertices[23].normal = XMFLOAT3(0.f, -1.f, 0.f);
117     mesh.vertices[23].tangent = XMFLOAT3(1.f, 0.f, 0.f);
118     mesh.vertices[23].tex = XMFLOAT2(1.f, 1.f);
119 
120     //構建索引
121     mesh.indices[0] = 0;
122     mesh.indices[1] = 1;
123     mesh.indices[2] = 2;
124     mesh.indices[3] = 0;
125     mesh.indices[4] = 2;
126     mesh.indices[5] = 3;
127 
128     mesh.indices[6] = 4;
129     mesh.indices[7] = 5;
130     mesh.indices[8] = 6;
131     mesh.indices[9] = 4;
132     mesh.indices[10] = 6;
133     mesh.indices[11] = 7;
134 
135     mesh.indices[12] = 8;
136     mesh.indices[13] = 9;
137     mesh.indices[14] = 10;
138     mesh.indices[15] = 8;
139     mesh.indices[16] = 10;
140     mesh.indices[17] = 11;
141 
142     mesh.indices[18] = 12;
143     mesh.indices[19] = 13;
144     mesh.indices[20] = 14;
145     mesh.indices[21] = 12;
146     mesh.indices[22] = 14;
147     mesh.indices[23] = 15;
148 
149     mesh.indices[24] = 16;
150     mesh.indices[25] = 17;
151     mesh.indices[26] = 18;
152     mesh.indices[27] = 16;
153     mesh.indices[28] = 18;
154     mesh.indices[29] = 19;
155 
156     mesh.indices[30] = 20;
157     mesh.indices[31] = 21;
158     mesh.indices[32] = 22;
159     mesh.indices[33] = 20;
160     mesh.indices[34] = 22;
161     mesh.indices[35] = 23;
162 }
View Code

1.3圓柱

  為了構建一個圓柱,需要提供如下信息:圓柱的上口半徑(topRadius),下口半徑(bottomRadius),高度(height)。此外,為了指定圓柱的精細度,還需要指定兩個參數,一個為沒高度方向上平均划分的個數(stack),另一個為沿圓周方向等分的個數(slice)。

  可以根據龍書中給出的圖理解一下:

 1 void GeometryGenerator::CreateCylinder(float topRadius, float bottomRadius, float height, int slice, int stack, MeshData &mesh)
 2 {
 3     mesh.vertices.clear();
 4     mesh.indices.clear();
 5 
 6     //從上到下每個stack半徑變化量:dRadius
 7     float dRadius = (bottomRadius - topRadius) / stack;
 8     //每個stack高度:dHeight
 9     float dHeight = height / stack;
10 
11     //每個圓周上頂點數量:slice+1
12     int vertsPerRow = slice + 1;
13     //頂點行數:stack+1
14     int nRows = stack + 1;
15 
16     //總頂點數
17     int nVerts = vertsPerRow * nRows;
18     //總索引數
19     int nIndices = slice * stack * 6;
20 
21     mesh.vertices.resize(nVerts);
22     mesh.indices.resize(nIndices);
23 
24     //頂部Y坐標
25     float topY = height * 0.5f;
26 
27     for (int i = 0; i < nRows; ++i)
28     {
29         float tmpY = topY - dHeight * i;
30         float tmpRadius = topRadius + i * dRadius;
31 
32         for (int j = 0; j < vertsPerRow; ++j)
33         {
34             float theta = XM_2PI * j / slice;
35             int index = i * vertsPerRow + j;
36             mesh.vertices[index].pos = XMFLOAT3(tmpRadius*cos(theta), tmpY, tmpRadius*sin(theta));
37         }
38     }
39 
40     UINT tmp(0);
41     for (int i = 0; i < stack; ++i)
42     {
43         for (int j = 0; j < slice; ++j)
44         {
45             mesh.indices[tmp] = i * vertsPerRow + j;
46             mesh.indices[tmp + 1] = (i + 1) * vertsPerRow + j + 1;
47             mesh.indices[tmp + 2] = (i + 1) * vertsPerRow + j;
48             mesh.indices[tmp + 3] = i * vertsPerRow + j;
49             mesh.indices[tmp + 4] = i * vertsPerRow + j + 1;
50             mesh.indices[tmp + 5] = (i + 1) * vertsPerRow + j + 1;
51 
52             tmp += 6;
53         }
54     }
55 }

 

1.4球

  繪制球基本參數只有一個半徑,但是同圓柱一樣為了指定精細程度也要給出stack和slice兩個參數,這里slice是從上極點沿球面到下極點的180度角等分。具體繪制可以看代碼理解:

 1 void GeometryGenerator::CreateSphere(float radius, int slice, int stack, MeshData &mesh)
 2 {
 3 
 4     mesh.vertices.clear();
 5     mesh.indices.clear();
 6 
 7     int vertsPerRow = slice + 1;
 8     int nRows = stack - 1;
 9 
10     int nVerts = vertsPerRow * nRows + 2;
11     int nIndices = (nRows - 1)*slice * 6 + slice * 6;
12 
13     mesh.vertices.resize(nVerts);
14     mesh.indices.resize(nIndices);
15 
16     for (int i = 1; i <= nRows; ++i)
17     {
18         float phy = XM_PI * i / stack;
19         float tmpRadius = radius * sin(phy);
20         for (int j = 0; j < vertsPerRow; ++j)
21         {
22             float theta = XM_2PI * j / slice;
23             UINT index = (i - 1)*vertsPerRow + j;
24 
25             float x = tmpRadius*cos(theta);
26             float y = radius*cos(phy);
27             float z = tmpRadius*sin(theta);
28 
29             //位置坐標
30             mesh.vertices[index].pos = XMFLOAT3(x, y, z);
31             //法線
32             XMVECTOR N = XMVectorSet(x, y, z, 0.f);
33             XMStoreFloat3(&mesh.vertices[index].normal, XMVector3Normalize(N));
34             //切線
35             XMVECTOR T = XMVectorSet(-sin(theta), 0.f, cos(theta), 0.f);
36             XMStoreFloat3(&mesh.vertices[index].tangent, XMVector3Normalize(T));
37             //紋理坐標
38             mesh.vertices[index].tex = XMFLOAT2(j*1.f / slice, i*1.f / stack);
39         }
40     }
41 
42     int size = vertsPerRow * nRows;
43     //添加頂部和底部兩個頂點信息
44     mesh.vertices[size].pos = XMFLOAT3(0.f, radius, 0.f);
45     mesh.vertices[size].normal = XMFLOAT3(0.f, 1.f, 0.f);
46     mesh.vertices[size].tangent = XMFLOAT3(1.f, 0.f, 0.f);
47     mesh.vertices[size].tex = XMFLOAT2(0.f, 0.f);
48 
49     mesh.vertices[size + 1].pos = XMFLOAT3(0.f, -radius, 0.f);
50     mesh.vertices[size + 1].normal = XMFLOAT3(0.f, -1.f, 0.f);
51     mesh.vertices[size + 1].tangent = XMFLOAT3(1.f, 0.f, 0.f);
52     mesh.vertices[size + 1].tex = XMFLOAT2(0.f, 1.f);
53 
54     UINT tmp(0);
55     int start1 = 0;
56     int start2 = mesh.vertices.size() - vertsPerRow - 2;
57     int top = size;
58     int bottom = size + 1;
59     for (int i = 0; i < slice; ++i)
60     {
61         mesh.indices[tmp] = top;
62         mesh.indices[tmp + 1] = start1 + i + 1;
63         mesh.indices[tmp + 2] = start1 + i;
64 
65         tmp += 3;
66     }
67 
68     for (int i = 0; i < slice; ++i)
69     {
70         mesh.indices[tmp] = bottom;
71         mesh.indices[tmp + 1] = start2 + i;
72         mesh.indices[tmp + 2] = start2 + i + 1;
73 
74         tmp += 3;
75     }
76 
77     for (int i = 0; i < nRows - 1; ++i)
78     {
79         for (int j = 0; j < slice; ++j)
80         {
81             mesh.indices[tmp] = i * vertsPerRow + j;
82             mesh.indices[tmp + 1] = (i + 1) * vertsPerRow + j + 1;
83             mesh.indices[tmp + 2] = (i + 1) * vertsPerRow + j;
84             mesh.indices[tmp + 3] = i * vertsPerRow + j;
85             mesh.indices[tmp + 4] = i * vertsPerRow + j + 1;
86             mesh.indices[tmp + 5] = (i + 1) * vertsPerRow + j + 1;
87 
88             tmp += 6;
89         }
90     }
91 }

 

2.場景繪制

2.1最終效果

 

2.2多個幾何體共享頂點索引緩沖區 

  我們一共繪制了四種幾何體:網格、立方體、球和圓柱,它們公用了一個頂點和索引緩沖區。這樣我們就需要在其中找出每個幾何體對應的位置。

為了在頂點、索引緩沖區中找到一個物體對應的位置,我們使用三個參數:該物體在頂點緩沖區中的起始位置(VStart),索引緩沖區中的起始位置(IStart),以及索引總數(totalIndices)。看龍書中的一幅圖就很容易理解了:

 

2.3設為線框模式繪制

  在Render函數中創建一個柵格化狀態ID3D11RasterizerState ,狀態描述中FillMode設為D3D11_FILL_WIREFRAME即可

 1 //設置為線框繪制模式
 2     D3D11_RASTERIZER_DESC rsDesc;
 3     ZeroMemory(&rsDesc, sizeof(rsDesc));
 4     rsDesc.CullMode = D3D11_CULL_BACK;
 5     rsDesc.DepthClipEnable = true;
 6     //D3D11_FILL_WIREFRAME以線框模式繪制,D3D11_FILL_SOLID是以實體模式繪制
 7     rsDesc.FillMode = D3D11_FILL_WIREFRAME; 
 8     rsDesc.FrontCounterClockwise = false;
 9     ID3D11RasterizerState *rsState(nullptr);
10     m_pd3dDevice->CreateRasterizerState(&rsDesc, &rsState);
11     m_pImmediateContext->RSSetState(rsState);

 

  源碼下載:http://files.cnblogs.com/files/zhangbaochong/GeoDrawDemo.zip


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM