|
|
@@ -0,0 +1,657 @@
|
|
|
+//***************************************************************************************
|
|
|
+// GeometryGenerator.cpp by Frank Luna (C) 2011 All Rights Reserved.
|
|
|
+//***************************************************************************************
|
|
|
+
|
|
|
+#include "GeometryGenerator.h"
|
|
|
+#include <algorithm>
|
|
|
+
|
|
|
+using namespace DirectX;
|
|
|
+
|
|
|
+GeometryGenerator::MeshData GeometryGenerator::CreateBox(float width, float height, float depth, uint32 numSubdivisions)
|
|
|
+{
|
|
|
+ MeshData meshData;
|
|
|
+
|
|
|
+ //
|
|
|
+ // Create the vertices.
|
|
|
+ //
|
|
|
+
|
|
|
+ Vertex v[24];
|
|
|
+
|
|
|
+ float w2 = 0.5f * width;
|
|
|
+ float h2 = 0.5f * height;
|
|
|
+ float d2 = 0.5f * depth;
|
|
|
+
|
|
|
+ // Fill in the front face vertex data.
|
|
|
+ v[0] = Vertex(-w2, -h2, -d2, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
+ v[1] = Vertex(-w2, +h2, -d2, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
+ v[2] = Vertex(+w2, +h2, -d2, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
|
|
|
+ v[3] = Vertex(+w2, -h2, -d2, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
|
|
|
+
|
|
|
+ // Fill in the back face vertex data.
|
|
|
+ v[4] = Vertex(-w2, -h2, +d2, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
|
|
|
+ v[5] = Vertex(+w2, -h2, +d2, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
+ v[6] = Vertex(+w2, +h2, +d2, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
+ v[7] = Vertex(-w2, +h2, +d2, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
|
|
|
+
|
|
|
+ // Fill in the top face vertex data.
|
|
|
+ v[8] = Vertex(-w2, +h2, -d2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
+ v[9] = Vertex(-w2, +h2, +d2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
+ v[10] = Vertex(+w2, +h2, +d2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
|
|
|
+ v[11] = Vertex(+w2, +h2, -d2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
|
|
|
+
|
|
|
+ // Fill in the bottom face vertex data.
|
|
|
+ v[12] = Vertex(-w2, -h2, -d2, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
|
|
|
+ v[13] = Vertex(+w2, -h2, -d2, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
+ v[14] = Vertex(+w2, -h2, +d2, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
+ v[15] = Vertex(-w2, -h2, +d2, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
|
|
|
+
|
|
|
+ // Fill in the left face vertex data.
|
|
|
+ v[16] = Vertex(-w2, -h2, +d2, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
|
|
|
+ v[17] = Vertex(-w2, +h2, +d2, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
|
|
|
+ v[18] = Vertex(-w2, +h2, -d2, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
|
|
|
+ v[19] = Vertex(-w2, -h2, -d2, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
|
|
|
+
|
|
|
+ // Fill in the right face vertex data.
|
|
|
+ v[20] = Vertex(+w2, -h2, -d2, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f);
|
|
|
+ v[21] = Vertex(+w2, +h2, -d2, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
|
+ v[22] = Vertex(+w2, +h2, +d2, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f);
|
|
|
+ v[23] = Vertex(+w2, -h2, +d2, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f);
|
|
|
+
|
|
|
+ meshData.Vertices.assign(&v[0], &v[24]);
|
|
|
+
|
|
|
+ //
|
|
|
+ // Create the indices.
|
|
|
+ //
|
|
|
+
|
|
|
+ uint32 i[36];
|
|
|
+
|
|
|
+ // Fill in the front face index data
|
|
|
+ i[0] = 0; i[1] = 1; i[2] = 2;
|
|
|
+ i[3] = 0; i[4] = 2; i[5] = 3;
|
|
|
+
|
|
|
+ // Fill in the back face index data
|
|
|
+ i[6] = 4; i[7] = 5; i[8] = 6;
|
|
|
+ i[9] = 4; i[10] = 6; i[11] = 7;
|
|
|
+
|
|
|
+ // Fill in the top face index data
|
|
|
+ i[12] = 8; i[13] = 9; i[14] = 10;
|
|
|
+ i[15] = 8; i[16] = 10; i[17] = 11;
|
|
|
+
|
|
|
+ // Fill in the bottom face index data
|
|
|
+ i[18] = 12; i[19] = 13; i[20] = 14;
|
|
|
+ i[21] = 12; i[22] = 14; i[23] = 15;
|
|
|
+
|
|
|
+ // Fill in the left face index data
|
|
|
+ i[24] = 16; i[25] = 17; i[26] = 18;
|
|
|
+ i[27] = 16; i[28] = 18; i[29] = 19;
|
|
|
+
|
|
|
+ // Fill in the right face index data
|
|
|
+ i[30] = 20; i[31] = 21; i[32] = 22;
|
|
|
+ i[33] = 20; i[34] = 22; i[35] = 23;
|
|
|
+
|
|
|
+ meshData.Indices32.assign(&i[0], &i[36]);
|
|
|
+
|
|
|
+ // Put a cap on the number of subdivisions.
|
|
|
+ numSubdivisions = std::min<uint32>(numSubdivisions, 6u);
|
|
|
+
|
|
|
+ for (uint32 i = 0; i < numSubdivisions; ++i)
|
|
|
+ Subdivide(meshData);
|
|
|
+
|
|
|
+ return meshData;
|
|
|
+}
|
|
|
+
|
|
|
+GeometryGenerator::MeshData GeometryGenerator::CreateSphere(float radius, uint32 sliceCount, uint32 stackCount)
|
|
|
+{
|
|
|
+ MeshData meshData;
|
|
|
+
|
|
|
+ //
|
|
|
+ // Compute the vertices stating at the top pole and moving down the stacks.
|
|
|
+ //
|
|
|
+
|
|
|
+ // Poles: note that there will be texture coordinate distortion as there is
|
|
|
+ // not a unique point on the texture map to assign to the pole when mapping
|
|
|
+ // a rectangular texture onto a sphere.
|
|
|
+ Vertex topVertex(0.0f, +radius, 0.0f, 0.0f, +1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
+ Vertex bottomVertex(0.0f, -radius, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
+
|
|
|
+ meshData.Vertices.push_back(topVertex);
|
|
|
+
|
|
|
+ float phiStep = XM_PI / stackCount;
|
|
|
+ float thetaStep = 2.0f * XM_PI / sliceCount;
|
|
|
+
|
|
|
+ // Compute vertices for each stack ring (do not count the poles as rings).
|
|
|
+ for (uint32 i = 1; i <= stackCount - 1; ++i)
|
|
|
+ {
|
|
|
+ float phi = i * phiStep;
|
|
|
+
|
|
|
+ // Vertices of ring.
|
|
|
+ for (uint32 j = 0; j <= sliceCount; ++j)
|
|
|
+ {
|
|
|
+ float theta = j * thetaStep;
|
|
|
+
|
|
|
+ Vertex v;
|
|
|
+
|
|
|
+ // spherical to cartesian
|
|
|
+ v.Position.x = radius * sinf(phi) * cosf(theta);
|
|
|
+ v.Position.y = radius * cosf(phi);
|
|
|
+ v.Position.z = radius * sinf(phi) * sinf(theta);
|
|
|
+
|
|
|
+ // Partial derivative of P with respect to theta
|
|
|
+ v.TangentU.x = -radius * sinf(phi) * sinf(theta);
|
|
|
+ v.TangentU.y = 0.0f;
|
|
|
+ v.TangentU.z = +radius * sinf(phi) * cosf(theta);
|
|
|
+
|
|
|
+ XMVECTOR T = XMLoadFloat3(&v.TangentU);
|
|
|
+ XMStoreFloat3(&v.TangentU, XMVector3Normalize(T));
|
|
|
+
|
|
|
+ XMVECTOR p = XMLoadFloat3(&v.Position);
|
|
|
+ XMStoreFloat3(&v.Normal, XMVector3Normalize(p));
|
|
|
+
|
|
|
+ v.TexC.x = theta / XM_2PI;
|
|
|
+ v.TexC.y = phi / XM_PI;
|
|
|
+
|
|
|
+ meshData.Vertices.push_back(v);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ meshData.Vertices.push_back(bottomVertex);
|
|
|
+
|
|
|
+ //
|
|
|
+ // Compute indices for top stack. The top stack was written first to the vertex buffer
|
|
|
+ // and connects the top pole to the first ring.
|
|
|
+ //
|
|
|
+
|
|
|
+ for (uint32 i = 1; i <= sliceCount; ++i)
|
|
|
+ {
|
|
|
+ meshData.Indices32.push_back(0);
|
|
|
+ meshData.Indices32.push_back(i + 1);
|
|
|
+ meshData.Indices32.push_back(i);
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+ // Compute indices for inner stacks (not connected to poles).
|
|
|
+ //
|
|
|
+
|
|
|
+ // Offset the indices to the index of the first vertex in the first ring.
|
|
|
+ // This is just skipping the top pole vertex.
|
|
|
+ uint32 baseIndex = 1;
|
|
|
+ uint32 ringVertexCount = sliceCount + 1;
|
|
|
+ for (uint32 i = 0; i < stackCount - 2; ++i)
|
|
|
+ {
|
|
|
+ for (uint32 j = 0; j < sliceCount; ++j)
|
|
|
+ {
|
|
|
+ meshData.Indices32.push_back(baseIndex + i * ringVertexCount + j);
|
|
|
+ meshData.Indices32.push_back(baseIndex + i * ringVertexCount + j + 1);
|
|
|
+ meshData.Indices32.push_back(baseIndex + (i + 1) * ringVertexCount + j);
|
|
|
+
|
|
|
+ meshData.Indices32.push_back(baseIndex + (i + 1) * ringVertexCount + j);
|
|
|
+ meshData.Indices32.push_back(baseIndex + i * ringVertexCount + j + 1);
|
|
|
+ meshData.Indices32.push_back(baseIndex + (i + 1) * ringVertexCount + j + 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+ // Compute indices for bottom stack. The bottom stack was written last to the vertex buffer
|
|
|
+ // and connects the bottom pole to the bottom ring.
|
|
|
+ //
|
|
|
+
|
|
|
+ // South pole vertex was added last.
|
|
|
+ uint32 southPoleIndex = (uint32)meshData.Vertices.size() - 1;
|
|
|
+
|
|
|
+ // Offset the indices to the index of the first vertex in the last ring.
|
|
|
+ baseIndex = southPoleIndex - ringVertexCount;
|
|
|
+
|
|
|
+ for (uint32 i = 0; i < sliceCount; ++i)
|
|
|
+ {
|
|
|
+ meshData.Indices32.push_back(southPoleIndex);
|
|
|
+ meshData.Indices32.push_back(baseIndex + i);
|
|
|
+ meshData.Indices32.push_back(baseIndex + i + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ return meshData;
|
|
|
+}
|
|
|
+
|
|
|
+void GeometryGenerator::Subdivide(MeshData& meshData)
|
|
|
+{
|
|
|
+ // Save a copy of the input geometry.
|
|
|
+ MeshData inputCopy = meshData;
|
|
|
+
|
|
|
+
|
|
|
+ meshData.Vertices.resize(0);
|
|
|
+ meshData.Indices32.resize(0);
|
|
|
+
|
|
|
+ // v1
|
|
|
+ // *
|
|
|
+ // / \
|
|
|
+ // / \
|
|
|
+ // m0*-----*m1
|
|
|
+ // / \ / \
|
|
|
+ // / \ / \
|
|
|
+ // *-----*-----*
|
|
|
+ // v0 m2 v2
|
|
|
+
|
|
|
+ uint32 numTris = (uint32)inputCopy.Indices32.size() / 3;
|
|
|
+ for (uint32 i = 0; i < numTris; ++i)
|
|
|
+ {
|
|
|
+ Vertex v0 = inputCopy.Vertices[inputCopy.Indices32[i * 3 + 0]];
|
|
|
+ Vertex v1 = inputCopy.Vertices[inputCopy.Indices32[i * 3 + 1]];
|
|
|
+ Vertex v2 = inputCopy.Vertices[inputCopy.Indices32[i * 3 + 2]];
|
|
|
+
|
|
|
+ //
|
|
|
+ // Generate the midpoints.
|
|
|
+ //
|
|
|
+
|
|
|
+ Vertex m0 = MidPoint(v0, v1);
|
|
|
+ Vertex m1 = MidPoint(v1, v2);
|
|
|
+ Vertex m2 = MidPoint(v0, v2);
|
|
|
+
|
|
|
+ //
|
|
|
+ // Add new geometry.
|
|
|
+ //
|
|
|
+
|
|
|
+ meshData.Vertices.push_back(v0); // 0
|
|
|
+ meshData.Vertices.push_back(v1); // 1
|
|
|
+ meshData.Vertices.push_back(v2); // 2
|
|
|
+ meshData.Vertices.push_back(m0); // 3
|
|
|
+ meshData.Vertices.push_back(m1); // 4
|
|
|
+ meshData.Vertices.push_back(m2); // 5
|
|
|
+
|
|
|
+ meshData.Indices32.push_back(i * 6 + 0);
|
|
|
+ meshData.Indices32.push_back(i * 6 + 3);
|
|
|
+ meshData.Indices32.push_back(i * 6 + 5);
|
|
|
+
|
|
|
+ meshData.Indices32.push_back(i * 6 + 3);
|
|
|
+ meshData.Indices32.push_back(i * 6 + 4);
|
|
|
+ meshData.Indices32.push_back(i * 6 + 5);
|
|
|
+
|
|
|
+ meshData.Indices32.push_back(i * 6 + 5);
|
|
|
+ meshData.Indices32.push_back(i * 6 + 4);
|
|
|
+ meshData.Indices32.push_back(i * 6 + 2);
|
|
|
+
|
|
|
+ meshData.Indices32.push_back(i * 6 + 3);
|
|
|
+ meshData.Indices32.push_back(i * 6 + 1);
|
|
|
+ meshData.Indices32.push_back(i * 6 + 4);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+GeometryGenerator::Vertex GeometryGenerator::MidPoint(const Vertex& v0, const Vertex& v1)
|
|
|
+{
|
|
|
+ XMVECTOR p0 = XMLoadFloat3(&v0.Position);
|
|
|
+ XMVECTOR p1 = XMLoadFloat3(&v1.Position);
|
|
|
+
|
|
|
+ XMVECTOR n0 = XMLoadFloat3(&v0.Normal);
|
|
|
+ XMVECTOR n1 = XMLoadFloat3(&v1.Normal);
|
|
|
+
|
|
|
+ XMVECTOR tan0 = XMLoadFloat3(&v0.TangentU);
|
|
|
+ XMVECTOR tan1 = XMLoadFloat3(&v1.TangentU);
|
|
|
+
|
|
|
+ XMVECTOR tex0 = XMLoadFloat2(&v0.TexC);
|
|
|
+ XMVECTOR tex1 = XMLoadFloat2(&v1.TexC);
|
|
|
+
|
|
|
+ // Compute the midpoints of all the attributes. Vectors need to be normalized
|
|
|
+ // since linear interpolating can make them not unit length.
|
|
|
+ XMVECTOR pos = 0.5f * (p0 + p1);
|
|
|
+ XMVECTOR normal = XMVector3Normalize(0.5f * (n0 + n1));
|
|
|
+ XMVECTOR tangent = XMVector3Normalize(0.5f * (tan0 + tan1));
|
|
|
+ XMVECTOR tex = 0.5f * (tex0 + tex1);
|
|
|
+
|
|
|
+ Vertex v;
|
|
|
+ XMStoreFloat3(&v.Position, pos);
|
|
|
+ XMStoreFloat3(&v.Normal, normal);
|
|
|
+ XMStoreFloat3(&v.TangentU, tangent);
|
|
|
+ XMStoreFloat2(&v.TexC, tex);
|
|
|
+
|
|
|
+ return v;
|
|
|
+}
|
|
|
+
|
|
|
+GeometryGenerator::MeshData GeometryGenerator::CreateGeosphere(float radius, uint32 numSubdivisions)
|
|
|
+{
|
|
|
+ MeshData meshData;
|
|
|
+
|
|
|
+ // Put a cap on the number of subdivisions.
|
|
|
+ numSubdivisions = std::min<uint32>(numSubdivisions, 6u);
|
|
|
+
|
|
|
+ // Approximate a sphere by tessellating an icosahedron.
|
|
|
+
|
|
|
+ const float X = 0.525731f;
|
|
|
+ const float Z = 0.850651f;
|
|
|
+
|
|
|
+ XMFLOAT3 pos[12] =
|
|
|
+ {
|
|
|
+ XMFLOAT3(-X, 0.0f, Z), XMFLOAT3(X, 0.0f, Z),
|
|
|
+ XMFLOAT3(-X, 0.0f, -Z), XMFLOAT3(X, 0.0f, -Z),
|
|
|
+ XMFLOAT3(0.0f, Z, X), XMFLOAT3(0.0f, Z, -X),
|
|
|
+ XMFLOAT3(0.0f, -Z, X), XMFLOAT3(0.0f, -Z, -X),
|
|
|
+ XMFLOAT3(Z, X, 0.0f), XMFLOAT3(-Z, X, 0.0f),
|
|
|
+ XMFLOAT3(Z, -X, 0.0f), XMFLOAT3(-Z, -X, 0.0f)
|
|
|
+ };
|
|
|
+
|
|
|
+ uint32 k[60] =
|
|
|
+ {
|
|
|
+ 1,4,0, 4,9,0, 4,5,9, 8,5,4, 1,8,4,
|
|
|
+ 1,10,8, 10,3,8, 8,3,5, 3,2,5, 3,7,2,
|
|
|
+ 3,10,7, 10,6,7, 6,11,7, 6,0,11, 6,1,0,
|
|
|
+ 10,1,6, 11,0,9, 2,11,9, 5,2,9, 11,2,7
|
|
|
+ };
|
|
|
+
|
|
|
+ meshData.Vertices.resize(12);
|
|
|
+ meshData.Indices32.assign(&k[0], &k[60]);
|
|
|
+
|
|
|
+ for (uint32 i = 0; i < 12; ++i)
|
|
|
+ meshData.Vertices[i].Position = pos[i];
|
|
|
+
|
|
|
+ for (uint32 i = 0; i < numSubdivisions; ++i)
|
|
|
+ Subdivide(meshData);
|
|
|
+
|
|
|
+ // Project vertices onto sphere and scale.
|
|
|
+ for (uint32 i = 0; i < meshData.Vertices.size(); ++i)
|
|
|
+ {
|
|
|
+ // Project onto unit sphere.
|
|
|
+ XMVECTOR n = XMVector3Normalize(XMLoadFloat3(&meshData.Vertices[i].Position));
|
|
|
+
|
|
|
+ // Project onto sphere.
|
|
|
+ XMVECTOR p = radius * n;
|
|
|
+
|
|
|
+ XMStoreFloat3(&meshData.Vertices[i].Position, p);
|
|
|
+ XMStoreFloat3(&meshData.Vertices[i].Normal, n);
|
|
|
+
|
|
|
+ // Derive texture coordinates from spherical coordinates.
|
|
|
+ float theta = atan2f(meshData.Vertices[i].Position.z, meshData.Vertices[i].Position.x);
|
|
|
+
|
|
|
+ // Put in [0, 2pi].
|
|
|
+ if (theta < 0.0f)
|
|
|
+ theta += XM_2PI;
|
|
|
+
|
|
|
+ float phi = acosf(meshData.Vertices[i].Position.y / radius);
|
|
|
+
|
|
|
+ meshData.Vertices[i].TexC.x = theta / XM_2PI;
|
|
|
+ meshData.Vertices[i].TexC.y = phi / XM_PI;
|
|
|
+
|
|
|
+ // Partial derivative of P with respect to theta
|
|
|
+ meshData.Vertices[i].TangentU.x = -radius * sinf(phi) * sinf(theta);
|
|
|
+ meshData.Vertices[i].TangentU.y = 0.0f;
|
|
|
+ meshData.Vertices[i].TangentU.z = +radius * sinf(phi) * cosf(theta);
|
|
|
+
|
|
|
+ XMVECTOR T = XMLoadFloat3(&meshData.Vertices[i].TangentU);
|
|
|
+ XMStoreFloat3(&meshData.Vertices[i].TangentU, XMVector3Normalize(T));
|
|
|
+ }
|
|
|
+
|
|
|
+ return meshData;
|
|
|
+}
|
|
|
+
|
|
|
+GeometryGenerator::MeshData GeometryGenerator::CreateCylinder(float bottomRadius, float topRadius, float height, uint32 sliceCount, uint32 stackCount)
|
|
|
+{
|
|
|
+ MeshData meshData;
|
|
|
+
|
|
|
+ //
|
|
|
+ // Build Stacks.
|
|
|
+ //
|
|
|
+
|
|
|
+ float stackHeight = height / stackCount;
|
|
|
+
|
|
|
+ // Amount to increment radius as we move up each stack level from bottom to top.
|
|
|
+ float radiusStep = (topRadius - bottomRadius) / stackCount;
|
|
|
+
|
|
|
+ uint32 ringCount = stackCount + 1;
|
|
|
+
|
|
|
+ // Compute vertices for each stack ring starting at the bottom and moving up.
|
|
|
+ for (uint32 i = 0; i < ringCount; ++i)
|
|
|
+ {
|
|
|
+ float y = -0.5f * height + i * stackHeight;
|
|
|
+ float r = bottomRadius + i * radiusStep;
|
|
|
+
|
|
|
+ // vertices of ring
|
|
|
+ float dTheta = 2.0f * XM_PI / sliceCount;
|
|
|
+ for (uint32 j = 0; j <= sliceCount; ++j)
|
|
|
+ {
|
|
|
+ Vertex vertex;
|
|
|
+
|
|
|
+ float c = cosf(j * dTheta);
|
|
|
+ float s = sinf(j * dTheta);
|
|
|
+
|
|
|
+ vertex.Position = XMFLOAT3(r * c, y, r * s);
|
|
|
+
|
|
|
+ vertex.TexC.x = (float)j / sliceCount;
|
|
|
+ vertex.TexC.y = 1.0f - (float)i / stackCount;
|
|
|
+
|
|
|
+ // Cylinder can be parameterized as follows, where we introduce v
|
|
|
+ // parameter that goes in the same direction as the v tex-coord
|
|
|
+ // so that the bitangent goes in the same direction as the v tex-coord.
|
|
|
+ // Let r0 be the bottom radius and let r1 be the top radius.
|
|
|
+ // y(v) = h - hv for v in [0,1].
|
|
|
+ // r(v) = r1 + (r0-r1)v
|
|
|
+ //
|
|
|
+ // x(t, v) = r(v)*cos(t)
|
|
|
+ // y(t, v) = h - hv
|
|
|
+ // z(t, v) = r(v)*sin(t)
|
|
|
+ //
|
|
|
+ // dx/dt = -r(v)*sin(t)
|
|
|
+ // dy/dt = 0
|
|
|
+ // dz/dt = +r(v)*cos(t)
|
|
|
+ //
|
|
|
+ // dx/dv = (r0-r1)*cos(t)
|
|
|
+ // dy/dv = -h
|
|
|
+ // dz/dv = (r0-r1)*sin(t)
|
|
|
+
|
|
|
+ // This is unit length.
|
|
|
+ vertex.TangentU = XMFLOAT3(-s, 0.0f, c);
|
|
|
+
|
|
|
+ float dr = bottomRadius - topRadius;
|
|
|
+ XMFLOAT3 bitangent(dr * c, -height, dr * s);
|
|
|
+
|
|
|
+ XMVECTOR T = XMLoadFloat3(&vertex.TangentU);
|
|
|
+ XMVECTOR B = XMLoadFloat3(&bitangent);
|
|
|
+ XMVECTOR N = XMVector3Normalize(XMVector3Cross(T, B));
|
|
|
+ XMStoreFloat3(&vertex.Normal, N);
|
|
|
+
|
|
|
+ meshData.Vertices.push_back(vertex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Add one because we duplicate the first and last vertex per ring
|
|
|
+ // since the texture coordinates are different.
|
|
|
+ uint32 ringVertexCount = sliceCount + 1;
|
|
|
+
|
|
|
+ // Compute indices for each stack.
|
|
|
+ for (uint32 i = 0; i < stackCount; ++i)
|
|
|
+ {
|
|
|
+ for (uint32 j = 0; j < sliceCount; ++j)
|
|
|
+ {
|
|
|
+ meshData.Indices32.push_back(i * ringVertexCount + j);
|
|
|
+ meshData.Indices32.push_back((i + 1) * ringVertexCount + j);
|
|
|
+ meshData.Indices32.push_back((i + 1) * ringVertexCount + j + 1);
|
|
|
+
|
|
|
+ meshData.Indices32.push_back(i * ringVertexCount + j);
|
|
|
+ meshData.Indices32.push_back((i + 1) * ringVertexCount + j + 1);
|
|
|
+ meshData.Indices32.push_back(i * ringVertexCount + j + 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ BuildCylinderTopCap(bottomRadius, topRadius, height, sliceCount, stackCount, meshData);
|
|
|
+ BuildCylinderBottomCap(bottomRadius, topRadius, height, sliceCount, stackCount, meshData);
|
|
|
+
|
|
|
+ return meshData;
|
|
|
+}
|
|
|
+
|
|
|
+void GeometryGenerator::BuildCylinderTopCap(float bottomRadius, float topRadius, float height,
|
|
|
+ uint32 sliceCount, uint32 stackCount, MeshData& meshData)
|
|
|
+{
|
|
|
+ uint32 baseIndex = (uint32)meshData.Vertices.size();
|
|
|
+
|
|
|
+ float y = 0.5f * height;
|
|
|
+ float dTheta = 2.0f * XM_PI / sliceCount;
|
|
|
+
|
|
|
+ // Duplicate cap ring vertices because the texture coordinates and normals differ.
|
|
|
+ for (uint32 i = 0; i <= sliceCount; ++i)
|
|
|
+ {
|
|
|
+ float x = topRadius * cosf(i * dTheta);
|
|
|
+ float z = topRadius * sinf(i * dTheta);
|
|
|
+
|
|
|
+ // Scale down by the height to try and make top cap texture coord area
|
|
|
+ // proportional to base.
|
|
|
+ float u = x / height + 0.5f;
|
|
|
+ float v = z / height + 0.5f;
|
|
|
+
|
|
|
+ meshData.Vertices.push_back(Vertex(x, y, z, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, u, v));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Cap center vertex.
|
|
|
+ meshData.Vertices.push_back(Vertex(0.0f, y, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f));
|
|
|
+
|
|
|
+ // Index of center vertex.
|
|
|
+ uint32 centerIndex = (uint32)meshData.Vertices.size() - 1;
|
|
|
+
|
|
|
+ for (uint32 i = 0; i < sliceCount; ++i)
|
|
|
+ {
|
|
|
+ meshData.Indices32.push_back(centerIndex);
|
|
|
+ meshData.Indices32.push_back(baseIndex + i + 1);
|
|
|
+ meshData.Indices32.push_back(baseIndex + i);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void GeometryGenerator::BuildCylinderBottomCap(float bottomRadius, float topRadius, float height,
|
|
|
+ uint32 sliceCount, uint32 stackCount, MeshData& meshData)
|
|
|
+{
|
|
|
+ //
|
|
|
+ // Build bottom cap.
|
|
|
+ //
|
|
|
+
|
|
|
+ uint32 baseIndex = (uint32)meshData.Vertices.size();
|
|
|
+ float y = -0.5f * height;
|
|
|
+
|
|
|
+ // vertices of ring
|
|
|
+ float dTheta = 2.0f * XM_PI / sliceCount;
|
|
|
+ for (uint32 i = 0; i <= sliceCount; ++i)
|
|
|
+ {
|
|
|
+ float x = bottomRadius * cosf(i * dTheta);
|
|
|
+ float z = bottomRadius * sinf(i * dTheta);
|
|
|
+
|
|
|
+ // Scale down by the height to try and make top cap texture coord area
|
|
|
+ // proportional to base.
|
|
|
+ float u = x / height + 0.5f;
|
|
|
+ float v = z / height + 0.5f;
|
|
|
+
|
|
|
+ meshData.Vertices.push_back(Vertex(x, y, z, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, u, v));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Cap center vertex.
|
|
|
+ meshData.Vertices.push_back(Vertex(0.0f, y, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f));
|
|
|
+
|
|
|
+ // Cache the index of center vertex.
|
|
|
+ uint32 centerIndex = (uint32)meshData.Vertices.size() - 1;
|
|
|
+
|
|
|
+ for (uint32 i = 0; i < sliceCount; ++i)
|
|
|
+ {
|
|
|
+ meshData.Indices32.push_back(centerIndex);
|
|
|
+ meshData.Indices32.push_back(baseIndex + i);
|
|
|
+ meshData.Indices32.push_back(baseIndex + i + 1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+GeometryGenerator::MeshData GeometryGenerator::CreateGrid(float width, float depth, uint32 m, uint32 n)
|
|
|
+{
|
|
|
+ MeshData meshData;
|
|
|
+
|
|
|
+ uint32 vertexCount = m * n;
|
|
|
+ uint32 faceCount = (m - 1) * (n - 1) * 2;
|
|
|
+
|
|
|
+ //
|
|
|
+ // Create the vertices.
|
|
|
+ //
|
|
|
+
|
|
|
+ float halfWidth = 0.5f * width;
|
|
|
+ float halfDepth = 0.5f * depth;
|
|
|
+
|
|
|
+ float dx = width / (n - 1);
|
|
|
+ float dz = depth / (m - 1);
|
|
|
+
|
|
|
+ float du = 1.0f / (n - 1);
|
|
|
+ float dv = 1.0f / (m - 1);
|
|
|
+
|
|
|
+ meshData.Vertices.resize(vertexCount);
|
|
|
+ for (uint32 i = 0; i < m; ++i)
|
|
|
+ {
|
|
|
+ float z = halfDepth - i * dz;
|
|
|
+ for (uint32 j = 0; j < n; ++j)
|
|
|
+ {
|
|
|
+ float x = -halfWidth + j * dx;
|
|
|
+
|
|
|
+ meshData.Vertices[i * n + j].Position = XMFLOAT3(x, 0.0f, z);
|
|
|
+ meshData.Vertices[i * n + j].Normal = XMFLOAT3(0.0f, 1.0f, 0.0f);
|
|
|
+ meshData.Vertices[i * n + j].TangentU = XMFLOAT3(1.0f, 0.0f, 0.0f);
|
|
|
+
|
|
|
+ // Stretch texture over grid.
|
|
|
+ meshData.Vertices[i * n + j].TexC.x = j * du;
|
|
|
+ meshData.Vertices[i * n + j].TexC.y = i * dv;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+ // Create the indices.
|
|
|
+ //
|
|
|
+
|
|
|
+ meshData.Indices32.resize(faceCount * 3); // 3 indices per face
|
|
|
+
|
|
|
+ // Iterate over each quad and compute indices.
|
|
|
+ uint32 k = 0;
|
|
|
+ for (uint32 i = 0; i < m - 1; ++i)
|
|
|
+ {
|
|
|
+ for (uint32 j = 0; j < n - 1; ++j)
|
|
|
+ {
|
|
|
+ meshData.Indices32[k] = i * n + j;
|
|
|
+ meshData.Indices32[k + 1] = i * n + j + 1;
|
|
|
+ meshData.Indices32[k + 2] = (i + 1) * n + j;
|
|
|
+
|
|
|
+ meshData.Indices32[k + 3] = (i + 1) * n + j;
|
|
|
+ meshData.Indices32[k + 4] = i * n + j + 1;
|
|
|
+ meshData.Indices32[k + 5] = (i + 1) * n + j + 1;
|
|
|
+
|
|
|
+ k += 6; // next quad
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return meshData;
|
|
|
+}
|
|
|
+
|
|
|
+GeometryGenerator::MeshData GeometryGenerator::CreateQuad(float x, float y, float w, float h, float depth)
|
|
|
+{
|
|
|
+ MeshData meshData;
|
|
|
+
|
|
|
+ meshData.Vertices.resize(4);
|
|
|
+ meshData.Indices32.resize(6);
|
|
|
+
|
|
|
+ // Position coordinates specified in NDC space.
|
|
|
+ meshData.Vertices[0] = Vertex(
|
|
|
+ x, y - h, depth,
|
|
|
+ 0.0f, 0.0f, -1.0f,
|
|
|
+ 1.0f, 0.0f, 0.0f,
|
|
|
+ 0.0f, 1.0f);
|
|
|
+
|
|
|
+ meshData.Vertices[1] = Vertex(
|
|
|
+ x, y, depth,
|
|
|
+ 0.0f, 0.0f, -1.0f,
|
|
|
+ 1.0f, 0.0f, 0.0f,
|
|
|
+ 0.0f, 0.0f);
|
|
|
+
|
|
|
+ meshData.Vertices[2] = Vertex(
|
|
|
+ x + w, y, depth,
|
|
|
+ 0.0f, 0.0f, -1.0f,
|
|
|
+ 1.0f, 0.0f, 0.0f,
|
|
|
+ 1.0f, 0.0f);
|
|
|
+
|
|
|
+ meshData.Vertices[3] = Vertex(
|
|
|
+ x + w, y - h, depth,
|
|
|
+ 0.0f, 0.0f, -1.0f,
|
|
|
+ 1.0f, 0.0f, 0.0f,
|
|
|
+ 1.0f, 1.0f);
|
|
|
+
|
|
|
+ meshData.Indices32[0] = 0;
|
|
|
+ meshData.Indices32[1] = 1;
|
|
|
+ meshData.Indices32[2] = 2;
|
|
|
+
|
|
|
+ meshData.Indices32[3] = 0;
|
|
|
+ meshData.Indices32[4] = 2;
|
|
|
+ meshData.Indices32[5] = 3;
|
|
|
+
|
|
|
+ return meshData;
|
|
|
+}
|