using System;
using System.Collections.Generic;
using UnityEngine;
namespace ProceduralToolkit
{
///
/// Helper class for procedural mesh generation
///
public partial class MeshDraft
{
#region Platonic solids
///
/// Constructs a tetrahedron draft
///
public static MeshDraft Tetrahedron(float radius, bool generateUV = true)
{
const float tetrahedralAngle = -19.471220333f;
var vertex0 = new Vector3(0, radius, 0);
var vertex1 = Geometry.PointOnSphere(radius, 0, tetrahedralAngle);
var vertex2 = Geometry.PointOnSphere(radius, 120, tetrahedralAngle);
var vertex3 = Geometry.PointOnSphere(radius, 240, tetrahedralAngle);
var draft = new MeshDraft {name = "Tetrahedron"};
if (generateUV)
{
var uv0 = new Vector2(0, 0);
var uv1 = new Vector2(0.5f, 1);
var uv2 = new Vector2(1, 0);
draft.AddTriangle(vertex2, vertex0, vertex1, true, uv0, uv1, uv2)
.AddTriangle(vertex2, vertex1, vertex3, true, uv0, uv1, uv2)
.AddTriangle(vertex3, vertex0, vertex2, true, uv0, uv1, uv2)
.AddTriangle(vertex1, vertex0, vertex3, true, uv0, uv1, uv2);
}
else
{
draft.AddTriangle(vertex2, vertex0, vertex1, true)
.AddTriangle(vertex2, vertex1, vertex3, true)
.AddTriangle(vertex3, vertex0, vertex2, true)
.AddTriangle(vertex1, vertex0, vertex3, true);
}
return draft;
}
///
/// Constructs a cube draft
///
public static MeshDraft Cube(float side, bool generateUV = true)
{
var draft = Hexahedron(side, side, side, generateUV);
draft.name = "Cube";
return draft;
}
///
/// Constructs a hexahedron draft
///
public static MeshDraft Hexahedron(float width, float length, float height, bool generateUV = true)
{
return Hexahedron(Vector3.right*width, Vector3.forward*length, Vector3.up*height, generateUV);
}
///
/// Constructs a hexahedron draft
///
public static MeshDraft Hexahedron(Vector3 width, Vector3 length, Vector3 height, bool generateUV = true)
{
Vector3 v000 = -width/2 - length/2 - height/2;
Vector3 v001 = v000 + height;
Vector3 v010 = v000 + width;
Vector3 v011 = v000 + width + height;
Vector3 v100 = v000 + length;
Vector3 v101 = v000 + length + height;
Vector3 v110 = v000 + width + length;
Vector3 v111 = v000 + width + length + height;
var draft = new MeshDraft {name = "Hexahedron"};
if (generateUV)
{
Vector2 uv0 = new Vector2(0, 0);
Vector2 uv1 = new Vector2(0, 1);
Vector2 uv2 = new Vector2(1, 1);
Vector2 uv3 = new Vector2(1, 0);
draft.AddQuad(v100, v101, v001, v000, Vector3.left, uv0, uv1, uv2, uv3)
.AddQuad(v010, v011, v111, v110, Vector3.right, uv0, uv1, uv2, uv3)
.AddQuad(v010, v110, v100, v000, Vector3.down, uv0, uv1, uv2, uv3)
.AddQuad(v111, v011, v001, v101, Vector3.up, uv0, uv1, uv2, uv3)
.AddQuad(v000, v001, v011, v010, Vector3.back, uv0, uv1, uv2, uv3)
.AddQuad(v110, v111, v101, v100, Vector3.forward, uv0, uv1, uv2, uv3);
}
else
{
draft.AddQuad(v100, v101, v001, v000, Vector3.left)
.AddQuad(v010, v011, v111, v110, Vector3.right)
.AddQuad(v010, v110, v100, v000, Vector3.down)
.AddQuad(v111, v011, v001, v101, Vector3.up)
.AddQuad(v000, v001, v011, v010, Vector3.back)
.AddQuad(v110, v111, v101, v100, Vector3.forward);
}
return draft;
}
///
/// Constructs a octahedron draft
///
public static MeshDraft Octahedron(float radius, bool generateUV = true)
{
var draft = BiPyramid(radius, 4, radius*2, generateUV);
draft.name = "Octahedron";
return draft;
}
///
/// Constructs a dodecahedron draft
///
public static MeshDraft Dodecahedron(float radius)
{
const float magicAngle1 = 52.62263590f;
const float magicAngle2 = 10.81231754f;
const float segmentAngle = 72;
float lowerAngle = 0;
float upperAngle = segmentAngle/2;
var lowerCap = new Vector3[5];
var lowerRing = new Vector3[5];
var upperCap = new Vector3[5];
var upperRing = new Vector3[5];
for (var i = 0; i < 5; i++)
{
lowerCap[i] = Geometry.PointOnSphere(radius, lowerAngle, -magicAngle1);
lowerRing[i] = Geometry.PointOnSphere(radius, lowerAngle, -magicAngle2);
upperCap[i] = Geometry.PointOnSphere(radius, upperAngle, magicAngle1);
upperRing[i] = Geometry.PointOnSphere(radius, upperAngle, magicAngle2);
lowerAngle += segmentAngle;
upperAngle += segmentAngle;
}
var draft = new MeshDraft {name = "Dodecahedron"}
.AddTriangleFan(upperCap, Vector3.up)
.AddFlatTriangleBand(upperRing, upperCap, false)
.AddFlatTriangleBand(lowerRing, upperRing, false)
.AddFlatTriangleBand(lowerCap, lowerRing, false)
.AddTriangleFan(lowerCap, Vector3.down, true);
return draft;
}
///
/// Constructs a icosahedron draft
///
public static MeshDraft Icosahedron(float radius, bool generateUV = true)
{
const float magicAngle = 26.56505f;
const float segmentAngle = 72;
float lowerAngle = 0;
float upperAngle = segmentAngle/2;
var lowerRing = new Vector3[5];
var upperRing = new Vector3[5];
for (var i = 0; i < 5; i++)
{
lowerRing[i] = Geometry.PointOnSphere(radius, lowerAngle, -magicAngle);
upperRing[i] = Geometry.PointOnSphere(radius, upperAngle, magicAngle);
lowerAngle += segmentAngle;
upperAngle += segmentAngle;
}
var draft = new MeshDraft {name = "Icosahedron"}
.AddBaselessPyramid(new Vector3(0, radius, 0), upperRing, generateUV)
.AddFlatTriangleBand(lowerRing, upperRing, generateUV)
.AddBaselessPyramid(new Vector3(0, -radius, 0), lowerRing, generateUV, true);
return draft;
}
#endregion Platonic solids
///
/// Constructs a quad draft
///
public static MeshDraft Quad(Vector3 origin, Vector3 width, Vector3 height, bool generateUV = true)
{
var draft = new MeshDraft {name = "Quad"};
if (generateUV)
{
draft.AddQuad(origin, width, height, true, new Vector2(0, 0), new Vector2(0, 1), new Vector2(1, 1), new Vector2(1, 0));
}
else
{
draft.AddQuad(origin, width, height, true);
}
return draft;
}
///
/// Constructs a quad draft
///
public static MeshDraft Quad(Vector3 vertex0, Vector3 vertex1, Vector3 vertex2, Vector3 vertex3, bool generateUV = true)
{
var draft = new MeshDraft {name = "Quad"};
if (generateUV)
{
draft.AddQuad(vertex0, vertex1, vertex2, vertex3, true, new Vector2(0, 0), new Vector2(0, 1), new Vector2(1, 1), new Vector2(1, 0));
}
else
{
draft.AddQuad(vertex0, vertex1, vertex2, vertex3, true);
}
return draft;
}
///
/// Constructs a plane draft
///
public static MeshDraft Plane(float xSize = 1, float zSize = 1, int xSegments = 1, int zSegments = 1, bool generateUV = true)
{
float xStep = xSize/xSegments;
float zStep = zSize/zSegments;
var vertexCount = (xSegments + 1)*(zSegments + 1);
var draft = new MeshDraft
{
name = "Plane",
vertices = new List(vertexCount),
triangles = new List(xSegments*zSegments*6),
normals = new List(vertexCount)
};
for (int z = 0; z <= zSegments; z++)
{
for (int x = 0; x <= xSegments; x++)
{
draft.vertices.Add(new Vector3(x*xStep, 0f, z*zStep));
draft.normals.Add(Vector3.up);
if (generateUV)
{
draft.uv.Add(new Vector2((float) x/xSegments, (float) z/zSegments));
}
}
}
int i = 0;
for (int z = 0; z < zSegments; z++)
{
for (int x = 0; x < xSegments; x++)
{
draft.triangles.Add(i);
draft.triangles.Add(i + xSegments + 1);
draft.triangles.Add(i + 1);
draft.triangles.Add(i + 1);
draft.triangles.Add(i + xSegments + 1);
draft.triangles.Add(i + xSegments + 2);
i++;
}
i++;
}
return draft;
}
///
/// Constructs a pyramid draft
///
public static MeshDraft Pyramid(float radius, int segments, float height, bool generateUV = true)
{
float segmentAngle = 360f/segments;
float currentAngle = 0;
var ring = new Vector3[segments];
for (var i = 0; i < segments; i++)
{
ring[i] = Geometry.PointOnCircle3XZ(radius, currentAngle);
currentAngle += segmentAngle;
}
var draft = new MeshDraft().AddBaselessPyramid(Vector3.up*height, ring, generateUV);
if (generateUV)
{
var fanUV = new Vector2[segments];
currentAngle = 0;
for (var i = 0; i < segments; i++)
{
Vector2 uv = Geometry.PointOnCircle2(0.5f, currentAngle) + new Vector2(0.5f, 0.5f);
uv.x = 1 - uv.x;
fanUV[i] = uv;
currentAngle += segmentAngle;
}
draft.AddTriangleFan(ring, Vector3.down, fanUV, true);
}
else
{
draft.AddTriangleFan(ring, Vector3.down, true);
}
draft.name = "Pyramid";
return draft;
}
///
/// Constructs a bipyramid draft
///
public static MeshDraft BiPyramid(float radius, int segments, float height, bool generateUV = true)
{
float segmentAngle = 360f/segments;
float currentAngle = 0;
var ring = new Vector3[segments];
for (var i = 0; i < segments; i++)
{
ring[i] = Geometry.PointOnCircle3XZ(radius, currentAngle);
currentAngle += segmentAngle;
}
var draft = new MeshDraft {name = "Bipyramid"}
.AddBaselessPyramid(Vector3.up*height/2, ring, generateUV)
.AddBaselessPyramid(Vector3.down*height/2, ring, generateUV, true);
return draft;
}
///
/// Constructs a prism draft
///
public static MeshDraft Prism(float radius, int segments, float height, bool generateUV = true)
{
float segmentAngle = 360f/segments;
float currentAngle = 0;
Vector3 halfHeightUp = Vector3.up*height/2;
var lowerRing = new List(segments);
var lowerDiskUV = new List();
var upperRing = new List(segments);
var upperDiskUV = new List();
for (var i = 0; i < segments; i++)
{
var point = Geometry.PointOnCircle3XZ(radius, currentAngle);
lowerRing.Add(point - halfHeightUp);
upperRing.Add(point + halfHeightUp);
if (generateUV)
{
Vector2 uv = Geometry.PointOnCircle2(0.5f, currentAngle) + new Vector2(0.5f, 0.5f);
upperDiskUV.Add(uv);
uv.x = 1 - uv.x;
lowerDiskUV.Add(uv);
}
currentAngle += segmentAngle;
}
var draft = new MeshDraft {name = "Prism"}
.AddFlatQuadBand(lowerRing, upperRing, generateUV);
if (generateUV)
{
draft.AddTriangleFan(upperRing, Vector3.up, upperDiskUV)
.AddTriangleFan(lowerRing, Vector3.down, lowerDiskUV, true);
}
else
{
draft.AddTriangleFan(upperRing, Vector3.up)
.AddTriangleFan(lowerRing, Vector3.down, true);
}
return draft;
}
///
/// Constructs a cylinder draft
///
public static MeshDraft Cylinder(float radius, int segments, float height, bool generateUV = true)
{
float segmentAngle = 360f/segments;
float currentAngle = 0;
Vector3 halfHeightUp = Vector3.up*height/2;
var draft = new MeshDraft {name = "Cylinder"};
var lowerRing = new List(segments);
var lowerDiskUV = new List();
var upperRing = new List(segments);
var upperDiskUV = new List();
var strip = new List();
var stripNormals = new List();
var stripUV = new List();
for (var i = 0; i < segments; i++)
{
AddCylinderPoints(radius, currentAngle, halfHeightUp, generateUV,
ref strip, ref stripUV, ref stripNormals, out Vector3 lowerVertex, out Vector3 upperVertex);
lowerRing.Add(lowerVertex);
upperRing.Add(upperVertex);
if (generateUV)
{
Vector2 uv = Geometry.PointOnCircle2(0.5f, currentAngle) + new Vector2(0.5f, 0.5f);
upperDiskUV.Add(uv);
uv.x = 1 - uv.x;
lowerDiskUV.Add(uv);
}
currentAngle += segmentAngle;
}
AddCylinderPoints(radius, currentAngle, halfHeightUp, generateUV,
ref strip, ref stripUV, ref stripNormals, out _, out _);
if (generateUV)
{
draft.AddTriangleFan(lowerRing, Vector3.down, lowerDiskUV, true);
draft.AddTriangleFan(upperRing, Vector3.up, upperDiskUV);
draft.AddTriangleStrip(strip, stripNormals, stripUV);
}
else
{
draft.AddTriangleFan(lowerRing, Vector3.down, true);
draft.AddTriangleFan(upperRing, Vector3.up);
draft.AddTriangleStrip(strip, stripNormals);
}
return draft;
}
private static void AddCylinderPoints(float radius, float currentAngle, Vector3 halfHeightUp, bool generateUV,
ref List vertices, ref List uv, ref List normals,
out Vector3 lowerVertex, out Vector3 upperVertex)
{
Vector3 normal = Geometry.PointOnCircle3XZ(1, currentAngle);
Vector3 point = normal*radius;
lowerVertex = point - halfHeightUp;
upperVertex = point + halfHeightUp;
vertices.Add(upperVertex);
normals.Add(normal);
vertices.Add(lowerVertex);
normals.Add(normal);
if (generateUV)
{
float u = 1 - currentAngle/360;
uv.Add(new Vector2(u, 1));
uv.Add(new Vector2(u, 0));
}
}
///
/// Constructs a flat sphere draft
///
public static MeshDraft FlatSphere(float radius, int horizontalSegments, int verticalSegments, bool generateUV = true)
{
var draft = FlatSpheroid(radius, radius, horizontalSegments, verticalSegments, generateUV);
draft.name = "Flat sphere";
return draft;
}
///
/// Constructs a flat spheroid draft
///
public static MeshDraft FlatSpheroid(float radius, float height, int horizontalSegments, int verticalSegments, bool generateUV = true)
{
var draft = FlatRevolutionSurface(Geometry.PointOnSpheroid, radius, height, horizontalSegments, verticalSegments, generateUV);
draft.name = "Flat spheroid";
return draft;
}
///
/// Constructs a flat teardrop draft
///
public static MeshDraft FlatTeardrop(float radius, float height, int horizontalSegments, int verticalSegments, bool generateUV = true)
{
var draft = FlatRevolutionSurface(Geometry.PointOnTeardrop, radius, height, horizontalSegments, verticalSegments, generateUV);
draft.name = "Flat teardrop";
return draft;
}
///
/// Constructs a flat revolution surface draft
///
public static MeshDraft FlatRevolutionSurface(
Func surfaceFunction,
float radius,
float height,
int horizontalSegments,
int verticalSegments,
bool generateUV = true)
{
float horizontalSegmentAngle = 360f/horizontalSegments;
float verticalSegmentAngle = 180f/verticalSegments;
float currentVerticalAngle = -90;
int horizontalCount = horizontalSegments + 1;
var ringsVertices = new List>(verticalSegments);
List> ringsUV = null;
if (generateUV)
{
ringsUV = new List>(verticalSegments);
}
for (int y = 0; y <= verticalSegments; y++)
{
float currentHorizontalAngle = 0f;
var ringVertices = new List(horizontalCount);
List ringUV = null;
if (generateUV)
{
ringUV = new List(horizontalCount);
}
for (int x = 0; x <= horizontalSegments; x++)
{
var point = surfaceFunction(radius, height, currentHorizontalAngle, currentVerticalAngle);
ringVertices.Add(point);
if (generateUV)
{
ringUV.Add(new Vector2(1 - (float) x/horizontalSegments, (float) y/verticalSegments));
}
currentHorizontalAngle += horizontalSegmentAngle;
}
ringsVertices.Add(ringVertices);
if (generateUV)
{
ringsUV.Add(ringUV);
}
currentVerticalAngle += verticalSegmentAngle;
}
var draft = new MeshDraft {name = "Flat revolution surface"};
for (int y = 0; y < ringsVertices.Count - 1; y++)
{
var lowerRingVertices = ringsVertices[y];
var upperRingVertices = ringsVertices[y + 1];
if (generateUV)
{
var lowerRingUV = ringsUV[y];
var upperRingUV = ringsUV[y + 1];
for (int x = 0; x < horizontalSegments; x++)
{
Vector3 v00 = lowerRingVertices[x + 1];
Vector3 v01 = upperRingVertices[x + 1];
Vector3 v11 = upperRingVertices[x];
Vector3 v10 = lowerRingVertices[x];
Vector2 uv00 = lowerRingUV[x + 1];
Vector2 uv01 = upperRingUV[x + 1];
Vector2 uv11 = upperRingUV[x];
Vector2 uv10 = lowerRingUV[x];
draft.AddQuad(v00, v01, v11, v10, true, uv00, uv01, uv11, uv10);
}
}
else
{
for (int x = 0; x < horizontalSegments; x++)
{
Vector3 v00 = lowerRingVertices[x + 1];
Vector3 v01 = upperRingVertices[x + 1];
Vector3 v11 = upperRingVertices[x];
Vector3 v10 = lowerRingVertices[x];
draft.AddQuad(v00, v01, v11, v10, true);
}
}
}
return draft;
}
///
/// Constructs a sphere draft
///
public static MeshDraft Sphere(float radius, int horizontalSegments, int verticalSegments, bool generateUV = true)
{
var draft = Spheroid(radius, radius, horizontalSegments, verticalSegments, generateUV);
draft.name = "Sphere";
return draft;
}
///
/// Constructs a spheroid draft
///
public static MeshDraft Spheroid(float radius, float height, int horizontalSegments, int verticalSegments, bool generateUV = true)
{
var draft = RevolutionSurface(Geometry.PointOnSpheroid, radius, height, horizontalSegments, verticalSegments, generateUV);
draft.name = "Spheroid";
return draft;
}
///
/// Constructs a teardrop draft
///
public static MeshDraft Teardrop(float radius, float height, int horizontalSegments, int verticalSegments, bool generateUV = true)
{
var draft = RevolutionSurface(Geometry.PointOnTeardrop, radius, height, horizontalSegments, verticalSegments, generateUV);
draft.name = "Teardrop";
return draft;
}
///
/// Constructs a revolution surface draft
///
public static MeshDraft RevolutionSurface(
Func surfaceFunction,
float radius,
float height,
int horizontalSegments,
int verticalSegments,
bool generateUV = true)
{
var draft = new MeshDraft {name = "Revolution surface"};
float horizontalSegmentAngle = 360f/horizontalSegments;
float verticalSegmentAngle = 180f/verticalSegments;
float currentVerticalAngle = -90;
for (int y = 0; y <= verticalSegments; y++)
{
float currentHorizontalAngle = 0f;
for (int x = 0; x <= horizontalSegments; x++)
{
Vector3 point = surfaceFunction(radius, height, currentHorizontalAngle, currentVerticalAngle);
draft.vertices.Add(point);
draft.normals.Add(point.normalized);
if (generateUV)
{
draft.uv.Add(new Vector2((float) x/horizontalSegments, (float) y/verticalSegments));
}
currentHorizontalAngle -= horizontalSegmentAngle;
}
currentVerticalAngle += verticalSegmentAngle;
}
// Extra vertices due to the uvmap seam
int horizontalCount = horizontalSegments + 1;
for (int ring = 0; ring < verticalSegments; ring++)
{
for (int i = 0; i < horizontalCount - 1; i++)
{
int i0 = ring*horizontalCount + i;
int i1 = (ring + 1)*horizontalCount + i;
int i2 = ring*horizontalCount + i + 1;
int i3 = (ring + 1)*horizontalCount + i + 1;
draft.triangles.Add(i0);
draft.triangles.Add(i1);
draft.triangles.Add(i2);
draft.triangles.Add(i2);
draft.triangles.Add(i1);
draft.triangles.Add(i3);
}
}
return draft;
}
///
/// Constructs a partial box with specified faces
///
public static MeshDraft PartialBox(Vector3 width, Vector3 depth, Vector3 height, Directions parts, bool generateUV = true)
{
Vector3 v000 = -width/2 - depth/2 - height/2;
Vector3 v001 = v000 + height;
Vector3 v010 = v000 + width;
Vector3 v011 = v000 + width + height;
Vector3 v100 = v000 + depth;
Vector3 v101 = v000 + depth + height;
Vector3 v110 = v000 + width + depth;
Vector3 v111 = v000 + width + depth + height;
var draft = new MeshDraft {name = "Partial box"};
if (generateUV)
{
Vector2 uv0 = new Vector2(0, 0);
Vector2 uv1 = new Vector2(0, 1);
Vector2 uv2 = new Vector2(1, 1);
Vector2 uv3 = new Vector2(1, 0);
if (parts.HasFlag(Directions.Left)) draft.AddQuad(v100, v101, v001, v000, true, uv0, uv1, uv2, uv3);
if (parts.HasFlag(Directions.Right)) draft.AddQuad(v010, v011, v111, v110, true, uv0, uv1, uv2, uv3);
if (parts.HasFlag(Directions.Down)) draft.AddQuad(v010, v110, v100, v000, true, uv0, uv1, uv2, uv3);
if (parts.HasFlag(Directions.Up)) draft.AddQuad(v111, v011, v001, v101, true, uv0, uv1, uv2, uv3);
if (parts.HasFlag(Directions.Back)) draft.AddQuad(v000, v001, v011, v010, true, uv0, uv1, uv2, uv3);
if (parts.HasFlag(Directions.Forward)) draft.AddQuad(v110, v111, v101, v100, true, uv0, uv1, uv2, uv3);
}
else
{
if (parts.HasFlag(Directions.Left)) draft.AddQuad(v100, v101, v001, v000, true);
if (parts.HasFlag(Directions.Right)) draft.AddQuad(v010, v011, v111, v110, true);
if (parts.HasFlag(Directions.Down)) draft.AddQuad(v010, v110, v100, v000, true);
if (parts.HasFlag(Directions.Up)) draft.AddQuad(v111, v011, v001, v101, true);
if (parts.HasFlag(Directions.Back)) draft.AddQuad(v000, v001, v011, v010, true);
if (parts.HasFlag(Directions.Forward)) draft.AddQuad(v110, v111, v101, v100, true);
}
return draft;
}
///
/// Constructs a capsule draft
///
/// The height of the capsule
/// The radius of the capsule
/// The number of radial segments. Defaults to 32
/// The number of end-cap rings. Defaults to 8
public static MeshDraft Capsule(float height, float radius, int segments = 32, int rings = 8)
{
float cylinderHeight = height - radius*2;
int vertexCount = 2*rings*segments + 2;
int triangleCount = 4*rings*segments;
float horizontalAngle = 360f/segments;
float verticalAngle = 90f/rings;
var vertices = new Vector3[vertexCount];
var normals = new Vector3[vertexCount];
var triangles = new int[3*triangleCount];
int vi = 2;
int ti = 0;
int topCapIndex = 0;
int bottomCapIndex = 1;
vertices[topCapIndex].Set(0, cylinderHeight/2 + radius, 0);
normals[topCapIndex].Set(0, 1, 0);
vertices[bottomCapIndex].Set(0, -cylinderHeight/2 - radius, 0);
normals[bottomCapIndex].Set(0, -1, 0);
for (int s = 0; s < segments; s++)
{
for (int r = 1; r <= rings; r++)
{
// Top cap vertex
Vector3 normal = Geometry.PointOnSphere(1, s*horizontalAngle, 90 - r*verticalAngle);
Vector3 vertex = new Vector3(
x: radius*normal.x,
y: radius*normal.y + cylinderHeight/2,
z: radius*normal.z);
vertices[vi] = vertex;
normals[vi] = normal;
vi++;
// Bottom cap vertex
vertices[vi].Set(vertex.x, -vertex.y, vertex.z);
normals[vi].Set(normal.x, -normal.y, normal.z);
vi++;
int top_s1r1 = vi - 2;
int top_s1r0 = vi - 4;
int bot_s1r1 = vi - 1;
int bot_s1r0 = vi - 3;
int top_s0r1 = top_s1r1 - 2*rings;
int top_s0r0 = top_s1r0 - 2*rings;
int bot_s0r1 = bot_s1r1 - 2*rings;
int bot_s0r0 = bot_s1r0 - 2*rings;
if (s == 0)
{
top_s0r1 += vertexCount - 2;
top_s0r0 += vertexCount - 2;
bot_s0r1 += vertexCount - 2;
bot_s0r0 += vertexCount - 2;
}
// Create cap triangles
if (r == 1)
{
triangles[3*ti + 0] = topCapIndex;
triangles[3*ti + 1] = top_s0r1;
triangles[3*ti + 2] = top_s1r1;
ti++;
triangles[3*ti + 0] = bottomCapIndex;
triangles[3*ti + 1] = bot_s1r1;
triangles[3*ti + 2] = bot_s0r1;
ti++;
}
else
{
triangles[3*ti + 0] = top_s1r0;
triangles[3*ti + 1] = top_s0r0;
triangles[3*ti + 2] = top_s1r1;
ti++;
triangles[3*ti + 0] = top_s0r0;
triangles[3*ti + 1] = top_s0r1;
triangles[3*ti + 2] = top_s1r1;
ti++;
triangles[3*ti + 0] = bot_s0r1;
triangles[3*ti + 1] = bot_s0r0;
triangles[3*ti + 2] = bot_s1r1;
ti++;
triangles[3*ti + 0] = bot_s0r0;
triangles[3*ti + 1] = bot_s1r0;
triangles[3*ti + 2] = bot_s1r1;
ti++;
}
}
// Create side triangles
int top_s1 = vi - 2;
int top_s0 = top_s1 - 2*rings;
int bot_s1 = vi - 1;
int bot_s0 = bot_s1 - 2*rings;
if (s == 0)
{
top_s0 += vertexCount - 2;
bot_s0 += vertexCount - 2;
}
triangles[3*ti + 0] = top_s0;
triangles[3*ti + 1] = bot_s1;
triangles[3*ti + 2] = top_s1;
ti++;
triangles[3*ti + 0] = bot_s0;
triangles[3*ti + 1] = bot_s1;
triangles[3*ti + 2] = top_s0;
ti++;
}
return new MeshDraft
{
name = "Capsule",
vertices = new List(vertices),
triangles = new List(triangles),
normals = new List(normals)
};
}
}
}