home *** CD-ROM | disk | FTP | other *** search
/ Introduction to 3D Game …ogramming with DirectX 12 / Introduction-to-3D-Game-Programming-with-DirectX-12.ISO / Code.Textures / Common / GeometryGenerator.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2016-03-02  |  19.5 KB  |  658 lines

  1. //***************************************************************************************
  2. // GeometryGenerator.cpp by Frank Luna (C) 2011 All Rights Reserved.
  3. //***************************************************************************************
  4.  
  5. #include "GeometryGenerator.h"
  6. #include <algorithm>
  7.  
  8. using namespace DirectX;
  9.  
  10. GeometryGenerator::MeshData GeometryGenerator::CreateBox(float width, float height, float depth, uint32 numSubdivisions)
  11. {
  12.     MeshData meshData;
  13.  
  14.     //
  15.     // Create the vertices.
  16.     //
  17.  
  18.     Vertex v[24];
  19.  
  20.     float w2 = 0.5f*width;
  21.     float h2 = 0.5f*height;
  22.     float d2 = 0.5f*depth;
  23.     
  24.     // Fill in the front face vertex data.
  25.     v[0] = Vertex(-w2, -h2, -d2, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
  26.     v[1] = Vertex(-w2, +h2, -d2, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
  27.     v[2] = Vertex(+w2, +h2, -d2, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
  28.     v[3] = Vertex(+w2, -h2, -d2, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
  29.  
  30.     // Fill in the back face vertex data.
  31.     v[4] = Vertex(-w2, -h2, +d2, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
  32.     v[5] = Vertex(+w2, -h2, +d2, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
  33.     v[6] = Vertex(+w2, +h2, +d2, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
  34.     v[7] = Vertex(-w2, +h2, +d2, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
  35.  
  36.     // Fill in the top face vertex data.
  37.     v[8]  = Vertex(-w2, +h2, -d2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
  38.     v[9]  = Vertex(-w2, +h2, +d2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
  39.     v[10] = Vertex(+w2, +h2, +d2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
  40.     v[11] = Vertex(+w2, +h2, -d2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
  41.  
  42.     // Fill in the bottom face vertex data.
  43.     v[12] = Vertex(-w2, -h2, -d2, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
  44.     v[13] = Vertex(+w2, -h2, -d2, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
  45.     v[14] = Vertex(+w2, -h2, +d2, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
  46.     v[15] = Vertex(-w2, -h2, +d2, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
  47.  
  48.     // Fill in the left face vertex data.
  49.     v[16] = Vertex(-w2, -h2, +d2, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
  50.     v[17] = Vertex(-w2, +h2, +d2, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
  51.     v[18] = Vertex(-w2, +h2, -d2, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
  52.     v[19] = Vertex(-w2, -h2, -d2, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
  53.  
  54.     // Fill in the right face vertex data.
  55.     v[20] = Vertex(+w2, -h2, -d2, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f);
  56.     v[21] = Vertex(+w2, +h2, -d2, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
  57.     v[22] = Vertex(+w2, +h2, +d2, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f);
  58.     v[23] = Vertex(+w2, -h2, +d2, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f);
  59.  
  60.     meshData.Vertices.assign(&v[0], &v[24]);
  61.  
  62.     //
  63.     // Create the indices.
  64.     //
  65.  
  66.     uint32 i[36];
  67.  
  68.     // Fill in the front face index data
  69.     i[0] = 0; i[1] = 1; i[2] = 2;
  70.     i[3] = 0; i[4] = 2; i[5] = 3;
  71.  
  72.     // Fill in the back face index data
  73.     i[6] = 4; i[7]  = 5; i[8]  = 6;
  74.     i[9] = 4; i[10] = 6; i[11] = 7;
  75.  
  76.     // Fill in the top face index data
  77.     i[12] = 8; i[13] =  9; i[14] = 10;
  78.     i[15] = 8; i[16] = 10; i[17] = 11;
  79.  
  80.     // Fill in the bottom face index data
  81.     i[18] = 12; i[19] = 13; i[20] = 14;
  82.     i[21] = 12; i[22] = 14; i[23] = 15;
  83.  
  84.     // Fill in the left face index data
  85.     i[24] = 16; i[25] = 17; i[26] = 18;
  86.     i[27] = 16; i[28] = 18; i[29] = 19;
  87.  
  88.     // Fill in the right face index data
  89.     i[30] = 20; i[31] = 21; i[32] = 22;
  90.     i[33] = 20; i[34] = 22; i[35] = 23;
  91.  
  92.     meshData.Indices32.assign(&i[0], &i[36]);
  93.  
  94.     // Put a cap on the number of subdivisions.
  95.     numSubdivisions = std::min<uint32>(numSubdivisions, 6u);
  96.  
  97.     for(uint32 i = 0; i < numSubdivisions; ++i)
  98.         Subdivide(meshData);
  99.  
  100.     return meshData;
  101. }
  102.  
  103. GeometryGenerator::MeshData GeometryGenerator::CreateSphere(float radius, uint32 sliceCount, uint32 stackCount)
  104. {
  105.     MeshData meshData;
  106.  
  107.     //
  108.     // Compute the vertices stating at the top pole and moving down the stacks.
  109.     //
  110.  
  111.     // Poles: note that there will be texture coordinate distortion as there is
  112.     // not a unique point on the texture map to assign to the pole when mapping
  113.     // a rectangular texture onto a sphere.
  114.     Vertex topVertex(0.0f, +radius, 0.0f, 0.0f, +1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
  115.     Vertex bottomVertex(0.0f, -radius, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
  116.  
  117.     meshData.Vertices.push_back( topVertex );
  118.  
  119.     float phiStep   = XM_PI/stackCount;
  120.     float thetaStep = 2.0f*XM_PI/sliceCount;
  121.  
  122.     // Compute vertices for each stack ring (do not count the poles as rings).
  123.     for(uint32 i = 1; i <= stackCount-1; ++i)
  124.     {
  125.         float phi = i*phiStep;
  126.  
  127.         // Vertices of ring.
  128.         for(uint32 j = 0; j <= sliceCount; ++j)
  129.         {
  130.             float theta = j*thetaStep;
  131.  
  132.             Vertex v;
  133.  
  134.             // spherical to cartesian
  135.             v.Position.x = radius*sinf(phi)*cosf(theta);
  136.             v.Position.y = radius*cosf(phi);
  137.             v.Position.z = radius*sinf(phi)*sinf(theta);
  138.  
  139.             // Partial derivative of P with respect to theta
  140.             v.TangentU.x = -radius*sinf(phi)*sinf(theta);
  141.             v.TangentU.y = 0.0f;
  142.             v.TangentU.z = +radius*sinf(phi)*cosf(theta);
  143.  
  144.             XMVECTOR T = XMLoadFloat3(&v.TangentU);
  145.             XMStoreFloat3(&v.TangentU, XMVector3Normalize(T));
  146.  
  147.             XMVECTOR p = XMLoadFloat3(&v.Position);
  148.             XMStoreFloat3(&v.Normal, XMVector3Normalize(p));
  149.  
  150.             v.TexC.x = theta / XM_2PI;
  151.             v.TexC.y = phi / XM_PI;
  152.  
  153.             meshData.Vertices.push_back( v );
  154.         }
  155.     }
  156.  
  157.     meshData.Vertices.push_back( bottomVertex );
  158.  
  159.     //
  160.     // Compute indices for top stack.  The top stack was written first to the vertex buffer
  161.     // and connects the top pole to the first ring.
  162.     //
  163.  
  164.     for(uint32 i = 1; i <= sliceCount; ++i)
  165.     {
  166.         meshData.Indices32.push_back(0);
  167.         meshData.Indices32.push_back(i+1);
  168.         meshData.Indices32.push_back(i);
  169.     }
  170.     
  171.     //
  172.     // Compute indices for inner stacks (not connected to poles).
  173.     //
  174.  
  175.     // Offset the indices to the index of the first vertex in the first ring.
  176.     // This is just skipping the top pole vertex.
  177.     uint32 baseIndex = 1;
  178.     uint32 ringVertexCount = sliceCount + 1;
  179.     for(uint32 i = 0; i < stackCount-2; ++i)
  180.     {
  181.         for(uint32 j = 0; j < sliceCount; ++j)
  182.         {
  183.             meshData.Indices32.push_back(baseIndex + i*ringVertexCount + j);
  184.             meshData.Indices32.push_back(baseIndex + i*ringVertexCount + j+1);
  185.             meshData.Indices32.push_back(baseIndex + (i+1)*ringVertexCount + j);
  186.  
  187.             meshData.Indices32.push_back(baseIndex + (i+1)*ringVertexCount + j);
  188.             meshData.Indices32.push_back(baseIndex + i*ringVertexCount + j+1);
  189.             meshData.Indices32.push_back(baseIndex + (i+1)*ringVertexCount + j+1);
  190.         }
  191.     }
  192.  
  193.     //
  194.     // Compute indices for bottom stack.  The bottom stack was written last to the vertex buffer
  195.     // and connects the bottom pole to the bottom ring.
  196.     //
  197.  
  198.     // South pole vertex was added last.
  199.     uint32 southPoleIndex = (uint32)meshData.Vertices.size()-1;
  200.  
  201.     // Offset the indices to the index of the first vertex in the last ring.
  202.     baseIndex = southPoleIndex - ringVertexCount;
  203.     
  204.     for(uint32 i = 0; i < sliceCount; ++i)
  205.     {
  206.         meshData.Indices32.push_back(southPoleIndex);
  207.         meshData.Indices32.push_back(baseIndex+i);
  208.         meshData.Indices32.push_back(baseIndex+i+1);
  209.     }
  210.  
  211.     return meshData;
  212. }
  213.  
  214. void GeometryGenerator::Subdivide(MeshData& meshData)
  215. {
  216.     // Save a copy of the input geometry.
  217.     MeshData inputCopy = meshData;
  218.  
  219.  
  220.     meshData.Vertices.resize(0);
  221.     meshData.Indices32.resize(0);
  222.  
  223.     //       v1
  224.     //       *
  225.     //      / \
  226.     //     /   \
  227.     //  m0*-----*m1
  228.     //   / \   / \
  229.     //  /   \ /   \
  230.     // *-----*-----*
  231.     // v0    m2     v2
  232.  
  233.     uint32 numTris = (uint32)inputCopy.Indices32.size()/3;
  234.     for(uint32 i = 0; i < numTris; ++i)
  235.     {
  236.         Vertex v0 = inputCopy.Vertices[ inputCopy.Indices32[i*3+0] ];
  237.         Vertex v1 = inputCopy.Vertices[ inputCopy.Indices32[i*3+1] ];
  238.         Vertex v2 = inputCopy.Vertices[ inputCopy.Indices32[i*3+2] ];
  239.  
  240.         //
  241.         // Generate the midpoints.
  242.         //
  243.  
  244.         Vertex m0 = MidPoint(v0, v1);
  245.         Vertex m1 = MidPoint(v1, v2);
  246.         Vertex m2 = MidPoint(v0, v2);
  247.  
  248.         //
  249.         // Add new geometry.
  250.         //
  251.  
  252.         meshData.Vertices.push_back(v0); // 0
  253.         meshData.Vertices.push_back(v1); // 1
  254.         meshData.Vertices.push_back(v2); // 2
  255.         meshData.Vertices.push_back(m0); // 3
  256.         meshData.Vertices.push_back(m1); // 4
  257.         meshData.Vertices.push_back(m2); // 5
  258.  
  259.         meshData.Indices32.push_back(i*6+0);
  260.         meshData.Indices32.push_back(i*6+3);
  261.         meshData.Indices32.push_back(i*6+5);
  262.  
  263.         meshData.Indices32.push_back(i*6+3);
  264.         meshData.Indices32.push_back(i*6+4);
  265.         meshData.Indices32.push_back(i*6+5);
  266.  
  267.         meshData.Indices32.push_back(i*6+5);
  268.         meshData.Indices32.push_back(i*6+4);
  269.         meshData.Indices32.push_back(i*6+2);
  270.  
  271.         meshData.Indices32.push_back(i*6+3);
  272.         meshData.Indices32.push_back(i*6+1);
  273.         meshData.Indices32.push_back(i*6+4);
  274.     }
  275. }
  276.  
  277. GeometryGenerator::Vertex GeometryGenerator::MidPoint(const Vertex& v0, const Vertex& v1)
  278. {
  279.     XMVECTOR p0 = XMLoadFloat3(&v0.Position);
  280.     XMVECTOR p1 = XMLoadFloat3(&v1.Position);
  281.  
  282.     XMVECTOR n0 = XMLoadFloat3(&v0.Normal);
  283.     XMVECTOR n1 = XMLoadFloat3(&v1.Normal);
  284.  
  285.     XMVECTOR tan0 = XMLoadFloat3(&v0.TangentU);
  286.     XMVECTOR tan1 = XMLoadFloat3(&v1.TangentU);
  287.  
  288.     XMVECTOR tex0 = XMLoadFloat2(&v0.TexC);
  289.     XMVECTOR tex1 = XMLoadFloat2(&v1.TexC);
  290.  
  291.     // Compute the midpoints of all the attributes.  Vectors need to be normalized
  292.     // since linear interpolating can make them not unit length.  
  293.     XMVECTOR pos = 0.5f*(p0 + p1);
  294.     XMVECTOR normal = XMVector3Normalize(0.5f*(n0 + n1));
  295.     XMVECTOR tangent = XMVector3Normalize(0.5f*(tan0+tan1));
  296.     XMVECTOR tex = 0.5f*(tex0 + tex1);
  297.  
  298.     Vertex v;
  299.     XMStoreFloat3(&v.Position, pos);
  300.     XMStoreFloat3(&v.Normal, normal);
  301.     XMStoreFloat3(&v.TangentU, tangent);
  302.     XMStoreFloat2(&v.TexC, tex);
  303.  
  304.     return v;
  305. }
  306.  
  307. GeometryGenerator::MeshData GeometryGenerator::CreateGeosphere(float radius, uint32 numSubdivisions)
  308. {
  309.     MeshData meshData;
  310.  
  311.     // Put a cap on the number of subdivisions.
  312.     numSubdivisions = std::min<uint32>(numSubdivisions, 6u);
  313.  
  314.     // Approximate a sphere by tessellating an icosahedron.
  315.  
  316.     const float X = 0.525731f; 
  317.     const float Z = 0.850651f;
  318.  
  319.     XMFLOAT3 pos[12] = 
  320.     {
  321.         XMFLOAT3(-X, 0.0f, Z),  XMFLOAT3(X, 0.0f, Z),  
  322.         XMFLOAT3(-X, 0.0f, -Z), XMFLOAT3(X, 0.0f, -Z),    
  323.         XMFLOAT3(0.0f, Z, X),   XMFLOAT3(0.0f, Z, -X), 
  324.         XMFLOAT3(0.0f, -Z, X),  XMFLOAT3(0.0f, -Z, -X),    
  325.         XMFLOAT3(Z, X, 0.0f),   XMFLOAT3(-Z, X, 0.0f), 
  326.         XMFLOAT3(Z, -X, 0.0f),  XMFLOAT3(-Z, -X, 0.0f)
  327.     };
  328.  
  329.     uint32 k[60] =
  330.     {
  331.         1,4,0,  4,9,0,  4,5,9,  8,5,4,  1,8,4,    
  332.         1,10,8, 10,3,8, 8,3,5,  3,2,5,  3,7,2,    
  333.         3,10,7, 10,6,7, 6,11,7, 6,0,11, 6,1,0, 
  334.         10,1,6, 11,0,9, 2,11,9, 5,2,9,  11,2,7 
  335.     };
  336.  
  337.     meshData.Vertices.resize(12);
  338.     meshData.Indices32.assign(&k[0], &k[60]);
  339.  
  340.     for(uint32 i = 0; i < 12; ++i)
  341.         meshData.Vertices[i].Position = pos[i];
  342.  
  343.     for(uint32 i = 0; i < numSubdivisions; ++i)
  344.         Subdivide(meshData);
  345.  
  346.     // Project vertices onto sphere and scale.
  347.     for(uint32 i = 0; i < meshData.Vertices.size(); ++i)
  348.     {
  349.         // Project onto unit sphere.
  350.         XMVECTOR n = XMVector3Normalize(XMLoadFloat3(&meshData.Vertices[i].Position));
  351.  
  352.         // Project onto sphere.
  353.         XMVECTOR p = radius*n;
  354.  
  355.         XMStoreFloat3(&meshData.Vertices[i].Position, p);
  356.         XMStoreFloat3(&meshData.Vertices[i].Normal, n);
  357.  
  358.         // Derive texture coordinates from spherical coordinates.
  359.         float theta = atan2f(meshData.Vertices[i].Position.z, meshData.Vertices[i].Position.x);
  360.  
  361.         // Put in [0, 2pi].
  362.         if(theta < 0.0f)
  363.             theta += XM_2PI;
  364.  
  365.         float phi = acosf(meshData.Vertices[i].Position.y / radius);
  366.  
  367.         meshData.Vertices[i].TexC.x = theta/XM_2PI;
  368.         meshData.Vertices[i].TexC.y = phi/XM_PI;
  369.  
  370.         // Partial derivative of P with respect to theta
  371.         meshData.Vertices[i].TangentU.x = -radius*sinf(phi)*sinf(theta);
  372.         meshData.Vertices[i].TangentU.y = 0.0f;
  373.         meshData.Vertices[i].TangentU.z = +radius*sinf(phi)*cosf(theta);
  374.  
  375.         XMVECTOR T = XMLoadFloat3(&meshData.Vertices[i].TangentU);
  376.         XMStoreFloat3(&meshData.Vertices[i].TangentU, XMVector3Normalize(T));
  377.     }
  378.  
  379.     return meshData;
  380. }
  381.  
  382. GeometryGenerator::MeshData GeometryGenerator::CreateCylinder(float bottomRadius, float topRadius, float height, uint32 sliceCount, uint32 stackCount)
  383. {
  384.     MeshData meshData;
  385.  
  386.     //
  387.     // Build Stacks.
  388.     // 
  389.  
  390.     float stackHeight = height / stackCount;
  391.  
  392.     // Amount to increment radius as we move up each stack level from bottom to top.
  393.     float radiusStep = (topRadius - bottomRadius) / stackCount;
  394.  
  395.     uint32 ringCount = stackCount+1;
  396.  
  397.     // Compute vertices for each stack ring starting at the bottom and moving up.
  398.     for(uint32 i = 0; i < ringCount; ++i)
  399.     {
  400.         float y = -0.5f*height + i*stackHeight;
  401.         float r = bottomRadius + i*radiusStep;
  402.  
  403.         // vertices of ring
  404.         float dTheta = 2.0f*XM_PI/sliceCount;
  405.         for(uint32 j = 0; j <= sliceCount; ++j)
  406.         {
  407.             Vertex vertex;
  408.  
  409.             float c = cosf(j*dTheta);
  410.             float s = sinf(j*dTheta);
  411.  
  412.             vertex.Position = XMFLOAT3(r*c, y, r*s);
  413.  
  414.             vertex.TexC.x = (float)j/sliceCount;
  415.             vertex.TexC.y = 1.0f - (float)i/stackCount;
  416.  
  417.             // Cylinder can be parameterized as follows, where we introduce v
  418.             // parameter that goes in the same direction as the v tex-coord
  419.             // so that the bitangent goes in the same direction as the v tex-coord.
  420.             //   Let r0 be the bottom radius and let r1 be the top radius.
  421.             //   y(v) = h - hv for v in [0,1].
  422.             //   r(v) = r1 + (r0-r1)v
  423.             //
  424.             //   x(t, v) = r(v)*cos(t)
  425.             //   y(t, v) = h - hv
  426.             //   z(t, v) = r(v)*sin(t)
  427.             // 
  428.             //  dx/dt = -r(v)*sin(t)
  429.             //  dy/dt = 0
  430.             //  dz/dt = +r(v)*cos(t)
  431.             //
  432.             //  dx/dv = (r0-r1)*cos(t)
  433.             //  dy/dv = -h
  434.             //  dz/dv = (r0-r1)*sin(t)
  435.  
  436.             // This is unit length.
  437.             vertex.TangentU = XMFLOAT3(-s, 0.0f, c);
  438.  
  439.             float dr = bottomRadius-topRadius;
  440.             XMFLOAT3 bitangent(dr*c, -height, dr*s);
  441.  
  442.             XMVECTOR T = XMLoadFloat3(&vertex.TangentU);
  443.             XMVECTOR B = XMLoadFloat3(&bitangent);
  444.             XMVECTOR N = XMVector3Normalize(XMVector3Cross(T, B));
  445.             XMStoreFloat3(&vertex.Normal, N);
  446.  
  447.             meshData.Vertices.push_back(vertex);
  448.         }
  449.     }
  450.  
  451.     // Add one because we duplicate the first and last vertex per ring
  452.     // since the texture coordinates are different.
  453.     uint32 ringVertexCount = sliceCount+1;
  454.  
  455.     // Compute indices for each stack.
  456.     for(uint32 i = 0; i < stackCount; ++i)
  457.     {
  458.         for(uint32 j = 0; j < sliceCount; ++j)
  459.         {
  460.             meshData.Indices32.push_back(i*ringVertexCount + j);
  461.             meshData.Indices32.push_back((i+1)*ringVertexCount + j);
  462.             meshData.Indices32.push_back((i+1)*ringVertexCount + j+1);
  463.  
  464.             meshData.Indices32.push_back(i*ringVertexCount + j);
  465.             meshData.Indices32.push_back((i+1)*ringVertexCount + j+1);
  466.             meshData.Indices32.push_back(i*ringVertexCount + j+1);
  467.         }
  468.     }
  469.  
  470.     BuildCylinderTopCap(bottomRadius, topRadius, height, sliceCount, stackCount, meshData);
  471.     BuildCylinderBottomCap(bottomRadius, topRadius, height, sliceCount, stackCount, meshData);
  472.  
  473.     return meshData;
  474. }
  475.  
  476. void GeometryGenerator::BuildCylinderTopCap(float bottomRadius, float topRadius, float height,
  477.                                             uint32 sliceCount, uint32 stackCount, MeshData& meshData)
  478. {
  479.     uint32 baseIndex = (uint32)meshData.Vertices.size();
  480.  
  481.     float y = 0.5f*height;
  482.     float dTheta = 2.0f*XM_PI/sliceCount;
  483.  
  484.     // Duplicate cap ring vertices because the texture coordinates and normals differ.
  485.     for(uint32 i = 0; i <= sliceCount; ++i)
  486.     {
  487.         float x = topRadius*cosf(i*dTheta);
  488.         float z = topRadius*sinf(i*dTheta);
  489.  
  490.         // Scale down by the height to try and make top cap texture coord area
  491.         // proportional to base.
  492.         float u = x/height + 0.5f;
  493.         float v = z/height + 0.5f;
  494.  
  495.         meshData.Vertices.push_back( Vertex(x, y, z, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, u, v) );
  496.     }
  497.  
  498.     // Cap center vertex.
  499.     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) );
  500.  
  501.     // Index of center vertex.
  502.     uint32 centerIndex = (uint32)meshData.Vertices.size()-1;
  503.  
  504.     for(uint32 i = 0; i < sliceCount; ++i)
  505.     {
  506.         meshData.Indices32.push_back(centerIndex);
  507.         meshData.Indices32.push_back(baseIndex + i+1);
  508.         meshData.Indices32.push_back(baseIndex + i);
  509.     }
  510. }
  511.  
  512. void GeometryGenerator::BuildCylinderBottomCap(float bottomRadius, float topRadius, float height,
  513.                                                uint32 sliceCount, uint32 stackCount, MeshData& meshData)
  514. {
  515.     // 
  516.     // Build bottom cap.
  517.     //
  518.  
  519.     uint32 baseIndex = (uint32)meshData.Vertices.size();
  520.     float y = -0.5f*height;
  521.  
  522.     // vertices of ring
  523.     float dTheta = 2.0f*XM_PI/sliceCount;
  524.     for(uint32 i = 0; i <= sliceCount; ++i)
  525.     {
  526.         float x = bottomRadius*cosf(i*dTheta);
  527.         float z = bottomRadius*sinf(i*dTheta);
  528.  
  529.         // Scale down by the height to try and make top cap texture coord area
  530.         // proportional to base.
  531.         float u = x/height + 0.5f;
  532.         float v = z/height + 0.5f;
  533.  
  534.         meshData.Vertices.push_back( Vertex(x, y, z, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, u, v) );
  535.     }
  536.  
  537.     // Cap center vertex.
  538.     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) );
  539.  
  540.     // Cache the index of center vertex.
  541.     uint32 centerIndex = (uint32)meshData.Vertices.size()-1;
  542.  
  543.     for(uint32 i = 0; i < sliceCount; ++i)
  544.     {
  545.         meshData.Indices32.push_back(centerIndex);
  546.         meshData.Indices32.push_back(baseIndex + i);
  547.         meshData.Indices32.push_back(baseIndex + i+1);
  548.     }
  549. }
  550.  
  551. GeometryGenerator::MeshData GeometryGenerator::CreateGrid(float width, float depth, uint32 m, uint32 n)
  552. {
  553.     MeshData meshData;
  554.  
  555.     uint32 vertexCount = m*n;
  556.     uint32 faceCount   = (m-1)*(n-1)*2;
  557.  
  558.     //
  559.     // Create the vertices.
  560.     //
  561.  
  562.     float halfWidth = 0.5f*width;
  563.     float halfDepth = 0.5f*depth;
  564.  
  565.     float dx = width / (n-1);
  566.     float dz = depth / (m-1);
  567.  
  568.     float du = 1.0f / (n-1);
  569.     float dv = 1.0f / (m-1);
  570.  
  571.     meshData.Vertices.resize(vertexCount);
  572.     for(uint32 i = 0; i < m; ++i)
  573.     {
  574.         float z = halfDepth - i*dz;
  575.         for(uint32 j = 0; j < n; ++j)
  576.         {
  577.             float x = -halfWidth + j*dx;
  578.  
  579.             meshData.Vertices[i*n+j].Position = XMFLOAT3(x, 0.0f, z);
  580.             meshData.Vertices[i*n+j].Normal   = XMFLOAT3(0.0f, 1.0f, 0.0f);
  581.             meshData.Vertices[i*n+j].TangentU = XMFLOAT3(1.0f, 0.0f, 0.0f);
  582.  
  583.             // Stretch texture over grid.
  584.             meshData.Vertices[i*n+j].TexC.x = j*du;
  585.             meshData.Vertices[i*n+j].TexC.y = i*dv;
  586.         }
  587.     }
  588.  
  589.     //
  590.     // Create the indices.
  591.     //
  592.  
  593.     meshData.Indices32.resize(faceCount*3); // 3 indices per face
  594.  
  595.     // Iterate over each quad and compute indices.
  596.     uint32 k = 0;
  597.     for(uint32 i = 0; i < m-1; ++i)
  598.     {
  599.         for(uint32 j = 0; j < n-1; ++j)
  600.         {
  601.             meshData.Indices32[k]   = i*n+j;
  602.             meshData.Indices32[k+1] = i*n+j+1;
  603.             meshData.Indices32[k+2] = (i+1)*n+j;
  604.  
  605.             meshData.Indices32[k+3] = (i+1)*n+j;
  606.             meshData.Indices32[k+4] = i*n+j+1;
  607.             meshData.Indices32[k+5] = (i+1)*n+j+1;
  608.  
  609.             k += 6; // next quad
  610.         }
  611.     }
  612.  
  613.     return meshData;
  614. }
  615.  
  616. GeometryGenerator::MeshData GeometryGenerator::CreateQuad(float x, float y, float w, float h, float depth)
  617. {
  618.     MeshData meshData;
  619.  
  620.     meshData.Vertices.resize(4);
  621.     meshData.Indices32.resize(6);
  622.  
  623.     // Position coordinates specified in NDC space.
  624.     meshData.Vertices[0] = Vertex(
  625.         x, y - h, depth,
  626.         0.0f, 0.0f, -1.0f,
  627.         1.0f, 0.0f, 0.0f,
  628.         0.0f, 1.0f);
  629.  
  630.     meshData.Vertices[1] = Vertex(
  631.         x, y, depth,
  632.         0.0f, 0.0f, -1.0f,
  633.         1.0f, 0.0f, 0.0f,
  634.         0.0f, 0.0f);
  635.  
  636.     meshData.Vertices[2] = Vertex(
  637.         x+w, y, depth,
  638.         0.0f, 0.0f, -1.0f,
  639.         1.0f, 0.0f, 0.0f,
  640.         1.0f, 0.0f);
  641.  
  642.     meshData.Vertices[3] = Vertex(
  643.         x+w, y-h, depth,
  644.         0.0f, 0.0f, -1.0f,
  645.         1.0f, 0.0f, 0.0f,
  646.         1.0f, 1.0f);
  647.  
  648.     meshData.Indices32[0] = 0;
  649.     meshData.Indices32[1] = 1;
  650.     meshData.Indices32[2] = 2;
  651.  
  652.     meshData.Indices32[3] = 0;
  653.     meshData.Indices32[4] = 2;
  654.     meshData.Indices32[5] = 3;
  655.  
  656.     return meshData;
  657. }
  658.