/// <summary> /// Adds mesh information from another draft /// </summary> public void Add(MeshDraft draft) { foreach (var triangle in draft.triangles) { triangles.Add(triangle + vertices.Count); } vertices.AddRange(draft.vertices); normals.AddRange(draft.normals); uv.AddRange(draft.uv); colors.AddRange(draft.colors); }
public static MeshDraft Band(List<Vector3> lowerRing, List<Vector3> upperRing) { var draft = new MeshDraft {name = "Band"}; if (lowerRing.Count < 3 || upperRing.Count < 3) { Debug.LogError("Array sizes must be greater than 2"); return draft; } if (lowerRing.Count != upperRing.Count) { Debug.LogError("Array sizes must be equal"); return draft; } draft.vertices.AddRange(lowerRing); draft.vertices.AddRange(upperRing); var lowerNormals = new List<Vector3>(); var upperNormals = new List<Vector3>(); var lowerUv = new List<Vector2>(); var upperUv = new List<Vector2>(); int i0, i1, i2, i3; Vector3 v0, v1, v2, v3; for (int i = 0; i < lowerRing.Count - 1; i++) { i0 = i; i1 = i + lowerRing.Count; i2 = i + 1; i3 = i + 1 + lowerRing.Count; v0 = draft.vertices[i0]; v1 = draft.vertices[i1]; v2 = draft.vertices[i2]; v3 = draft.vertices[i3]; draft.triangles.AddRange(new[] {i0, i1, i2}); draft.triangles.AddRange(new[] {i2, i1, i3}); lowerNormals.Add(Vector3.Cross(v1 - v0, v2 - v0).normalized); upperNormals.Add(Vector3.Cross(v3 - v1, v0 - v1).normalized); var u = (float) i/(lowerRing.Count - 1); lowerUv.Add(new Vector2(u, 0)); upperUv.Add(new Vector2(u, 1)); } i0 = lowerRing.Count - 1; i1 = lowerRing.Count*2 - 1; i2 = 0; i3 = lowerRing.Count; v0 = draft.vertices[i0]; v1 = draft.vertices[i1]; v2 = draft.vertices[i2]; v3 = draft.vertices[i3]; draft.triangles.AddRange(new[] {i0, i1, i2}); draft.triangles.AddRange(new[] {i2, i1, i3}); lowerNormals.Add(Vector3.Cross(v1 - v0, v2 - v0).normalized); upperNormals.Add(Vector3.Cross(v3 - v1, v0 - v1).normalized); draft.normals.AddRange(lowerNormals); draft.normals.AddRange(upperNormals); lowerUv.Add(new Vector2(1, 0)); upperUv.Add(new Vector2(1, 1)); draft.uv.AddRange(lowerUv); draft.uv.AddRange(upperUv); return draft; }
public static MeshDraft RevolutionSurface( Func <float, float, float, float, Vector3> surfaceFunction, float radius, float height, int horizontalSegments, int verticalSegments) { var draft = new MeshDraft { name = "Revolution surface" }; float horizontalSegmentAngle = 360f / horizontalSegments; float verticalSegmentAngle = 180f / verticalSegments; float currentVerticalAngle = -90; for (int ring = 0; ring <= verticalSegments; ring++) { float currentHorizontalAngle = 0f; for (int i = 0; i < horizontalSegments; i++) { Vector3 point = surfaceFunction(radius, height, currentHorizontalAngle, currentVerticalAngle); draft.vertices.Add(point); draft.normals.Add(point.normalized); draft.uv.Add(new Vector2((float)i / horizontalSegments, (float)ring / verticalSegments)); currentHorizontalAngle -= horizontalSegmentAngle; } currentVerticalAngle += verticalSegmentAngle; } for (int ring = 0; ring < verticalSegments; ring++) { int i0, i1, i2, i3; for (int i = 0; i < horizontalSegments - 1; i++) { i0 = ring * horizontalSegments + i; i1 = (ring + 1) * horizontalSegments + i; i2 = ring * horizontalSegments + i + 1; i3 = (ring + 1) * horizontalSegments + 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); } i0 = (ring + 1) * horizontalSegments - 1; i1 = (ring + 2) * horizontalSegments - 1; i2 = ring * horizontalSegments; i3 = (ring + 1) * horizontalSegments; 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); }
public static Mesh Prism(float radius, int segments, float height) { return(MeshDraft.Prism(radius, segments, height).ToMesh()); }
public static MeshDraft BaselessPyramid(Vector3 baseCenter, Vector3 apex, float radius, int segments, bool inverted = false) { float segmentAngle = Mathf.PI*2/segments*(inverted ? -1 : 1); float currentAngle = 0f; var vertices = new Vector3[segments + 1]; vertices[0] = apex; for (var i = 1; i <= segments; i++) { vertices[i] = PTUtils.PointOnCircle3(radius, currentAngle) + baseCenter; currentAngle += segmentAngle; } var draft = new MeshDraft {name = "BaselessPyramid"}; for (var i = 1; i < segments; i++) { draft.Add(Triangle(vertices[0], vertices[i], vertices[i + 1])); } draft.Add(Triangle(vertices[0], vertices[vertices.Length - 1], vertices[1])); return draft; }
/// <remarks> /// https://en.wikipedia.org/wiki/Triangle_fan /// </remarks> public static MeshDraft TriangleFan(List<Vector3> vertices) { var draft = new MeshDraft { vertices = vertices, triangles = new List<int>(vertices.Count - 2), normals = new List<Vector3>(vertices.Count), uv = new List<Vector2>(vertices.Count), name = "TriangleFan" }; for (int i = 1; i < vertices.Count - 1; i++) { draft.triangles.Add(0); draft.triangles.Add(i); draft.triangles.Add(i + 1); } var normal = Vector3.Cross(vertices[1] - vertices[0], vertices[2] - vertices[0]).normalized; for (int i = 0; i < vertices.Count; i++) { draft.normals.Add(normal); draft.uv.Add(new Vector2((float) i/vertices.Count, (float) i/vertices.Count)); } return draft; }
public static MeshDraft Plane(float xSize = 1, float zSize = 1, int xSegments = 1, int zSegments = 1) { float xStep = xSize/xSegments; float zStep = zSize/zSegments; var vertexCount = (xSegments + 1)*(zSegments + 1); var draft = new MeshDraft { name = "Plane", vertices = new List<Vector3>(vertexCount), triangles = new List<int>(xSegments*zSegments*6), normals = new List<Vector3>(vertexCount), uv = new List<Vector2>(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); 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; }
public static MeshDraft FlatSphere(float radius, int longitudeSegments, int latitudeSegments) { float longitudeSegmentAngle = Mathf.PI*2/longitudeSegments; float latitudeSegmentAngle = Mathf.PI/latitudeSegments; float currentLatitude = -Mathf.PI/2; var rings = new List<List<Vector3>>(latitudeSegments); for (var i = 0; i <= latitudeSegments; i++) { var currentLongitude = 0f; var ring = new List<Vector3>(longitudeSegments); for (int j = 0; j < longitudeSegments; j++) { ring.Add(PTUtils.PointOnSphere(radius, currentLongitude, currentLatitude)); currentLongitude -= longitudeSegmentAngle; } rings.Add(ring); currentLatitude += latitudeSegmentAngle; } var draft = new MeshDraft {name = "Flat sphere"}; for (int i = 0; i < rings.Count - 1; i++) { draft.Add(FlatBand(rings[i], rings[i + 1])); } return draft; }
public static Mesh Icosahedron(float radius) { return(MeshDraft.Icosahedron(radius).ToMesh()); }
public static Mesh Dodecahedron(float radius) { return(MeshDraft.Dodecahedron(radius).ToMesh()); }
public static Mesh Hexahedron(Vector3 width, Vector3 length, Vector3 height) { return(MeshDraft.Hexahedron(width, length, height).ToMesh()); }
public static Mesh Hexahedron(float width, float length, float height) { return(MeshDraft.Hexahedron(width, length, height).ToMesh()); }
public static Mesh TriangleStrip(List <Vector3> vertices) { return(MeshDraft.TriangleStrip(vertices).ToMesh()); }
public static Mesh Sphere(float radius, int longitudeSegments, int latitudeSegments) { return(MeshDraft.Sphere(radius, longitudeSegments, latitudeSegments).ToMesh()); }
public static Mesh Cylinder(float radius, int segments, float height) { return(MeshDraft.Cylinder(radius, segments, height).ToMesh()); }
public static MeshDraft BaselessPyramid(Vector3 apex, List<Vector3> ring) { var draft = new MeshDraft {name = "BaselessPyramid"}; for (var i = 0; i < ring.Count - 1; i++) { draft.Add(Triangle(apex, ring[i], ring[i + 1])); } draft.Add(Triangle(apex, ring[ring.Count - 1], ring[0])); return draft; }
public static MeshDraft FlatBand(List<Vector3> lowerRing, List<Vector3> upperRing) { var draft = new MeshDraft {name = "Flat band"}; if (lowerRing.Count < 3 || upperRing.Count < 3) { Debug.LogError("Array sizes must be greater than 2"); return draft; } if (lowerRing.Count != upperRing.Count) { Debug.LogError("Array sizes must be equal"); return draft; } Vector3 v0, v1, v2, v3; for (int i = 0; i < lowerRing.Count - 1; i++) { v0 = lowerRing[i]; v1 = upperRing[i]; v2 = lowerRing[i + 1]; v3 = upperRing[i + 1]; draft.Add(Triangle(v0, v1, v2)); draft.Add(Triangle(v2, v1, v3)); } v0 = lowerRing[lowerRing.Count - 1]; v1 = upperRing[upperRing.Count - 1]; v2 = lowerRing[0]; v3 = upperRing[0]; draft.Add(Triangle(v0, v1, v2)); draft.Add(Triangle(v2, v1, v3)); return draft; }
public static Mesh Plane(float xSize = 1, float zSize = 1, int xSegments = 1, int zSegments = 1) { return(MeshDraft.Plane(xSize, zSize, xSegments, zSegments).ToMesh()); }
/// <summary> /// Constructs partial hexahedron aka cube with specified faces /// </summary> public static MeshDraft Hexahedron(Vector3 width, Vector3 length, Vector3 height, Directions parts) { Vector3 corner0 = -width/2 - length/2 - height/2; Vector3 corner1 = width/2 + length/2 + height/2; var draft = new MeshDraft {name = "Hexahedron"}; if ((parts & Directions.Left) == Directions.Left) { draft.Add(Quad(corner0, height, length)); } if ((parts & Directions.Right) == Directions.Right) { draft.Add(Quad(corner1, -length, -height)); } if ((parts & Directions.Down) == Directions.Down) { draft.Add(Quad(corner0, length, width)); } if ((parts & Directions.Up) == Directions.Up) { draft.Add(Quad(corner1, -width, -length)); } if ((parts & Directions.Back) == Directions.Back) { draft.Add(Quad(corner0, width, height)); } if ((parts & Directions.Forward) == Directions.Forward) { draft.Add(Quad(corner1, -height, -width)); } return draft; }
public static MeshDraft BandDraft(List <Vector3> lowerRing, List <Vector3> upperRing) { var draft = new MeshDraft { name = "Band" }; if (lowerRing.Count < 3 || upperRing.Count < 3) { Debug.LogError("Array sizes must be greater than 2"); return(draft); } if (lowerRing.Count != upperRing.Count) { Debug.LogError("Array sizes must be equal"); return(draft); } draft.vertices.AddRange(lowerRing); draft.vertices.AddRange(upperRing); var lowerNormals = new List <Vector3>(); var upperNormals = new List <Vector3>(); var lowerUv = new List <Vector2>(); var upperUv = new List <Vector2>(); int i0, i1, i2, i3; Vector3 v0, v1, v2, v3; for (int i = 0; i < lowerRing.Count - 1; i++) { i0 = i; i1 = i + lowerRing.Count; i2 = i + 1; i3 = i + 1 + lowerRing.Count; v0 = draft.vertices[i0]; v1 = draft.vertices[i1]; v2 = draft.vertices[i2]; v3 = draft.vertices[i3]; draft.triangles.AddRange(new[] { i0, i1, i2 }); draft.triangles.AddRange(new[] { i2, i1, i3 }); lowerNormals.Add(Vector3.Cross(v1 - v0, v2 - v0).normalized); upperNormals.Add(Vector3.Cross(v3 - v1, v0 - v1).normalized); var u = (float)i / (lowerRing.Count - 1); lowerUv.Add(new Vector2(u, 0)); upperUv.Add(new Vector2(u, 1)); } i0 = lowerRing.Count - 1; i1 = lowerRing.Count * 2 - 1; i2 = 0; i3 = lowerRing.Count; v0 = draft.vertices[i0]; v1 = draft.vertices[i1]; v2 = draft.vertices[i2]; v3 = draft.vertices[i3]; draft.triangles.AddRange(new[] { i0, i1, i2 }); draft.triangles.AddRange(new[] { i2, i1, i3 }); lowerNormals.Add(Vector3.Cross(v1 - v0, v2 - v0).normalized); upperNormals.Add(Vector3.Cross(v3 - v1, v0 - v1).normalized); draft.normals.AddRange(lowerNormals); draft.normals.AddRange(upperNormals); lowerUv.Add(new Vector2(1, 0)); upperUv.Add(new Vector2(1, 1)); draft.uv.AddRange(lowerUv); draft.uv.AddRange(upperUv); return(draft); }
public static MeshDraft Sphere(float radius, int longitudeSegments, int latitudeSegments) { var draft = new MeshDraft {name = "Sphere"}; float longitudeSegmentAngle = Mathf.PI*2/longitudeSegments; float latitudeSegmentAngle = Mathf.PI/latitudeSegments; float currentLatitude = -Mathf.PI/2; for (var ring = 0; ring <= latitudeSegments; ring++) { var currentLongitude = 0f; for (int i = 0; i < longitudeSegments; i++) { var point = PTUtils.PointOnSphere(radius, currentLongitude, currentLatitude); draft.vertices.Add(point); draft.normals.Add(point.normalized); draft.uv.Add(new Vector2((float) i/longitudeSegments, (float) ring/latitudeSegments)); currentLongitude -= longitudeSegmentAngle; } currentLatitude += latitudeSegmentAngle; } int i0, i1, i2, i3; for (int ring = 0; ring < latitudeSegments; ring++) { for (int i = 0; i < longitudeSegments - 1; i++) { i0 = ring*longitudeSegments + i; i1 = (ring + 1)*longitudeSegments + i; i2 = ring*longitudeSegments + i + 1; i3 = (ring + 1)*longitudeSegments + i + 1; draft.triangles.AddRange(new[] {i0, i1, i2}); draft.triangles.AddRange(new[] {i2, i1, i3}); } i0 = (ring + 1)*longitudeSegments - 1; i1 = (ring + 2)*longitudeSegments - 1; i2 = ring*longitudeSegments; i3 = (ring + 1)*longitudeSegments; draft.triangles.AddRange(new[] {i0, i1, i2}); draft.triangles.AddRange(new[] {i2, i1, i3}); } return draft; }
/// <summary> /// Constructs a flat revolution surface draft /// </summary> public static MeshDraft FlatRevolutionSurface( Func <float, float, float, float, Vector3> 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 <List <Vector3> >(verticalSegments); var ringsUV = new List <List <Vector2> >(verticalSegments); for (int y = 0; y <= verticalSegments; y++) { float currentHorizontalAngle = 0f; var ringVertices = new List <Vector3>(horizontalCount); var ringUV = new List <Vector2>(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); 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]; 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, uv00, uv01, uv11, uv10); } } return(draft); }
/// <remarks> /// https://en.wikipedia.org/wiki/Triangle_strip /// </remarks> public static MeshDraft TriangleStrip(List<Vector3> vertices) { var draft = new MeshDraft { vertices = vertices, triangles = new List<int>(vertices.Count - 2), normals = new List<Vector3>(vertices.Count), uv = new List<Vector2>(vertices.Count), name = "TriangleStrip" }; for (int i = 0, j = 1, k = 2; i < vertices.Count - 2; i++, j += i%2*2, k += (i + 1)%2*2) { draft.triangles.Add(i); draft.triangles.Add(j); draft.triangles.Add(k); } var normal = Vector3.Cross(vertices[1] - vertices[0], vertices[2] - vertices[0]).normalized; for (int i = 0; i < vertices.Count; i++) { draft.normals.Add(normal); draft.uv.Add(new Vector2((float) i/vertices.Count, (float) i/vertices.Count)); } return draft; }
/// <summary> /// Constructs a revolution surface draft /// </summary> public static MeshDraft RevolutionSurface( Func <float, float, float, float, Vector3> surfaceFunction, float radius, float height, int horizontalSegments, int verticalSegments, bool generateUV = true, float domeDegrees = 0f) { var draft = new MeshDraft { name = "Revolution surface" }; float horizontalSegmentAngle = 360f / horizontalSegments; float verticalSegmentAngle = 180f / verticalSegments; float currentVerticalAngle = -90; // Calculate vertical segments required if we need to build a dome if (domeDegrees != 0f) { verticalSegments = (int)(domeDegrees / (360f / verticalSegments)); } int startY = 0; int endY = verticalSegments; int stepY = 1; for (int y = startY; (stepY == 1 ? y <= endY : y >= endY); y += stepY) { 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 = (startY > 0 ? startY - 1 : startY); (stepY == 1 ? ring <endY : ring> endY); ring += stepY) { 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); }
/// <summary> /// Constructs a partial box with specified faces /// </summary> public static MeshDraft PartialBox(Vector3 width, Vector3 length, Vector3 height, Directions parts, 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 = "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, Vector3.left, uv0, uv1, uv2, uv3); } if (parts.HasFlag(Directions.Right)) { draft.AddQuad(v010, v011, v111, v110, Vector3.right, uv0, uv1, uv2, uv3); } if (parts.HasFlag(Directions.Down)) { draft.AddQuad(v010, v110, v100, v000, Vector3.down, uv0, uv1, uv2, uv3); } if (parts.HasFlag(Directions.Up)) { draft.AddQuad(v111, v011, v001, v101, Vector3.up, uv0, uv1, uv2, uv3); } if (parts.HasFlag(Directions.Back)) { draft.AddQuad(v000, v001, v011, v010, Vector3.back, uv0, uv1, uv2, uv3); } if (parts.HasFlag(Directions.Forward)) { draft.AddQuad(v110, v111, v101, v100, Vector3.forward, uv0, uv1, uv2, uv3); } } else { if (parts.HasFlag(Directions.Left)) { draft.AddQuad(v100, v101, v001, v000, Vector3.left); } if (parts.HasFlag(Directions.Right)) { draft.AddQuad(v010, v011, v111, v110, Vector3.right); } if (parts.HasFlag(Directions.Down)) { draft.AddQuad(v010, v110, v100, v000, Vector3.down); } if (parts.HasFlag(Directions.Up)) { draft.AddQuad(v111, v011, v001, v101, Vector3.up); } if (parts.HasFlag(Directions.Back)) { draft.AddQuad(v000, v001, v011, v010, Vector3.back); } if (parts.HasFlag(Directions.Forward)) { draft.AddQuad(v110, v111, v101, v100, Vector3.forward); } } return(draft); }
public static Mesh Pyramid(float radius, int segments, float height, bool inverted = false) { return(MeshDraft.Pyramid(radius, segments, height, inverted).ToMesh()); }