练习题5 胶囊体

超4000字无法进行评论,所以把我的 “胶囊” 的代码放在这里^_^。

胶囊 = 半球壳 + 圆柱侧面 + 半球壳

  1     template<class VertexType, class IndexType>
  2     inline MeshData<VertexType, IndexType> CreateCapsule(float radius, UINT levels, UINT slices, const DirectX::XMFLOAT4 & color)
  3     {
  4         using namespace DirectX;
  5 
  6         MeshData<VertexType, IndexType> meshData;
  7         UINT vertexCount = 2 + (levels ) * (slices + 1) + 2 * (slices + 1); // 计算好空间
  8         UINT indexCount = 6 * (levels ) * slices + 6 * slices;
  9         meshData.vertexVec.resize(vertexCount);
 10         meshData.indexVec.resize(indexCount);
 11 
 12         Internal::VertexData vertexData;
 13         IndexType vIndex = 0, iIndex = 0;
 14 
 15         float phi = 0.0f, theta = 0.0f;
 16         float per_phi = XM_PI / levels;
 17         float per_theta = XM_2PI / slices;
 18         float x, y, z;
 19 
 20         //
 21         // 绘制顶部半球壳 放顶点-》放层级点-》放顶点索引-》放层级点索引
 22         //
 23 
 24         // 放入顶端点
 25         vertexData = { XMFLOAT3(0.0f, radius + 1.0f, 0.0f), XMFLOAT3(0.0f, 1.0f, 0.0f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f), color, XMFLOAT2(0.0f, 0.0f) };
 26         Internal::InsertVertexElement(meshData.vertexVec[vIndex++], vertexData);
 27 
 28         // 放入中间上层 顶点
 29         for (UINT i = 1; i <= levels / 2; ++i)// 要多填一层顶点供使用
 30         {
 31             phi = per_phi * i;
 32             // 需要slices + 1个顶点是因为 起点和终点需为同一点,但纹理坐标值不一致
 33             for (UINT j = 0; j <= slices; ++j)
 34             {
 35                 theta = per_theta * j;
 36                 x = radius * sinf(phi) * cosf(theta);
 37                 y = radius * cosf(phi) + 1.0f;
 38                 z = radius * sinf(phi) * sinf(theta);
 39                 // 计算出局部坐标、法向量、Tangent向量和纹理坐标
 40                 XMFLOAT3 pos = XMFLOAT3(x, y, z), normal;
 41                 XMStoreFloat3(&normal, XMVector3Normalize(XMLoadFloat3(&pos)));
 42 
 43                 vertexData = { pos, normal, XMFLOAT4(-sinf(theta), 0.0f, cosf(theta), 1.0f), color, XMFLOAT2(theta / XM_2PI, phi / XM_PI) };
 44                 Internal::InsertVertexElement(meshData.vertexVec[vIndex++], vertexData);
 45             }
 46         }
 47 
 48         // 放入顶点三角形索引
 49         if (levels > 1)
 50         {
 51             for (UINT j = 1; j <= slices; ++j)
 52             {
 53                 meshData.indexVec[iIndex++] = 0;
 54                 meshData.indexVec[iIndex++] = j % (slices + 1) + 1;
 55                 meshData.indexVec[iIndex++] = j;
 56             }
 57         }
 58 
 59         // 放入中间上层三角形索引
 60         for (UINT i = 1; i < levels / 2; ++i)// 处理索引则要少一层,cause 上一层顶点负责绘制本层三角面片
 61         {
 62             for (UINT j = 1; j <= slices; ++j)
 63             {
 64                 meshData.indexVec[iIndex++] = (i - 1) * (slices + 1) + j;
 65                 meshData.indexVec[iIndex++] = (i - 1) * (slices + 1) + j % (slices + 1) + 1;
 66                 meshData.indexVec[iIndex++] = i * (slices + 1) + j % (slices + 1) + 1;
 67 
 68                 meshData.indexVec[iIndex++] = i * (slices + 1) + j % (slices + 1) + 1;
 69                 meshData.indexVec[iIndex++] = i * (slices + 1) + j;
 70                 meshData.indexVec[iIndex++] = (i - 1) * (slices + 1) + j;
 71             }
 72         }
 73 
 74         //
 75         // 绘制中部圆柱侧面 放上面圆顶点-》放下面圆顶点-》放索引点
 76         //
 77 
 78         UINT vIndex_cur = vIndex; // 当前顶点数
 79         float height = 2.0f, h2 = height / 2;
 80         // 放入侧面顶端点
 81         for (UINT i = 0; i <= slices; ++i)
 82         {
 83             theta = i * per_theta;
 84             vertexData = { XMFLOAT3(radius * cosf(theta), h2, radius * sinf(theta)), XMFLOAT3(cosf(theta), 0.0f, sinf(theta)),
 85                 XMFLOAT4(-sinf(theta), 0.0f, cosf(theta), 1.0f), color, XMFLOAT2(theta / XM_2PI, 0.0f) };
 86             Internal::InsertVertexElement(meshData.vertexVec[vIndex++], vertexData);
 87         }
 88         // 放入侧面底端点
 89         for (UINT i = 0; i <= slices; ++i)
 90         {
 91             theta = i * per_theta;
 92             vertexData = { XMFLOAT3(radius * cosf(theta), -h2, radius * sinf(theta)), XMFLOAT3(cosf(theta), 0.0f, sinf(theta)),
 93                 XMFLOAT4(-sinf(theta), 0.0f, cosf(theta), 1.0f), color, XMFLOAT2(theta / XM_2PI, 1.0f) };
 94             Internal::InsertVertexElement(meshData.vertexVec[vIndex++], vertexData);
 95         }
 96         // 放入索引,注意更新顶点索引值
 97         for (UINT i = vIndex_cur; i < vIndex_cur + slices; ++i)
 98         {
 99             meshData.indexVec[iIndex++] = i;
100             meshData.indexVec[iIndex++] = i + 1;
101             meshData.indexVec[iIndex++] = (slices + 1) + i + 1;
102 
103             meshData.indexVec[iIndex++] = (slices + 1) + i + 1;
104             meshData.indexVec[iIndex++] = (slices + 1) + i;
105             meshData.indexVec[iIndex++] = i;
106         }
107 
108         //
109         // 绘制底部半球壳 放层级点-》放底部顶点-》放层级索引-》放底部顶点索引
110         //
111 
112         UINT add = 2 * (slices + 1); // 圆柱顶点数,用于确定下半球壳顶点索引
113 
114         // 放入中间下层 层级点
115         for (UINT i = levels/2+1; i < levels ; ++i)// 要多填一层顶点供使用
116         {
117             phi = per_phi * i;
118             // 需要slices + 1个顶点是因为 起点和终点需为同一点,但纹理坐标值不一致
119             for (UINT j = 0; j <= slices; ++j)
120             {
121                 theta = per_theta * j;
122                 x = radius * sinf(phi) * cosf(theta);
123                 y = radius * cosf(phi) - 1.0f;
124                 z = radius * sinf(phi) * sinf(theta);
125                 // 计算出局部坐标、法向量、Tangent向量和纹理坐标
126                 XMFLOAT3 pos = XMFLOAT3(x, y, z), normal;
127                 XMStoreFloat3(&normal, XMVector3Normalize(XMLoadFloat3(&pos)));
128 
129                 vertexData = { pos, normal, XMFLOAT4(-sinf(theta), 0.0f, cosf(theta), 1.0f), color, XMFLOAT2(theta / XM_2PI, phi / XM_PI) };
130                 Internal::InsertVertexElement(meshData.vertexVec[vIndex++], vertexData);
131             }
132         }
133 
134         // 放入底端点
135         vertexData = { XMFLOAT3(0.0f, -radius-1.0f, 0.0f), XMFLOAT3(0.0f, -1.0f, 0.0f),
136             XMFLOAT4(-1.0f, 0.0f, 0.0f, 1.0f), color, XMFLOAT2(0.0f, 1.0f) };
137         Internal::InsertVertexElement(meshData.vertexVec[vIndex++], vertexData);
138 
139         // 放入中间下层索引,注意顶点索引值
140         for (UINT i = levels / 2; i < levels - 1; ++i)// 处理索引则要少一层,cause 上一层顶点负责绘制本层三角面片
141         {
142             for (UINT j = 1; j <= slices; ++j)
143             {
144                 meshData.indexVec[iIndex++] = add + (i - 1) * (slices + 1) + j;
145                 meshData.indexVec[iIndex++] = add + (i - 1) * (slices + 1) + j % (slices + 1) + 1;
146                 meshData.indexVec[iIndex++] = add + i * (slices + 1) + j % (slices + 1) + 1;
147 
148                 meshData.indexVec[iIndex++] = add + i * (slices + 1) + j % (slices + 1) + 1;
149                 meshData.indexVec[iIndex++] = add + i * (slices + 1) + j;
150                 meshData.indexVec[iIndex++] = add + (i - 1) * (slices + 1) + j;
151             }
152         }
153 
154         // 放入底端顶点索引,注意顶点索引值(最下面一层)
155         if (levels > 1)
156         {
157             for (UINT j = 1; j <= slices; ++j)
158             {
159                 meshData.indexVec[iIndex++] = add + (levels - 2) * (slices + 1) + j;
160                 meshData.indexVec[iIndex++] = add + (levels - 2) * (slices + 1) + j % (slices + 1) + 1;
161                 meshData.indexVec[iIndex++] = add + (levels - 1) * (slices + 1) + 1;
162             }
163         }
164 
165         return meshData;
166     }

效果:

posted @ 2020-01-16 19:27  yocichen  阅读(475)  评论(0)    收藏  举报