using UnityEngine; using System.Linq; using System.Collections; using System.Collections.Generic; using UnityEngine.ProBuilder.Poly2Tri; using UnityEngine.ProBuilder; namespace UnityEngine.ProBuilder.MeshOperations { /// /// Wrapper around Triangle.NET triangulation methods. https://github.com/zon/triangle /// static class Triangulation { /// /// Given a set of points this method will format the points into a boundary contour and triangulate, returning /// a set of indexes that corresponds to the original ordering. /// /// /// /// /// public static bool SortAndTriangulate(IList points, out List indexes, bool convex = false) { IList sorted = Projection.Sort(points, SortMethod.CounterClockwise); Dictionary map = new Dictionary(); for (int i = 0; i < sorted.Count; i++) map.Add(i, points.IndexOf(sorted[i])); if (!Triangulate(sorted, out indexes, convex)) return false; for (int i = 0; i < indexes.Count; i++) indexes[i] = map[indexes[i]]; return true; } /// /// Attempts to triangulate a set of vertices. If unordered is specified as false vertices will not be re-ordered before triangulation. /// /// /// /// /// /// public static bool TriangulateVertices(IList vertices, out List triangles, bool unordered = true, bool convex = false) { Vector3[] facePoints = new Vector3[vertices.Count]; for (int i = 0; i < vertices.Count; ++i) facePoints[i] = vertices[i].position; return TriangulateVertices(facePoints, out triangles, unordered, convex); } public static bool TriangulateVertices(Vector3[] vertices, out List triangles, bool unordered = true, bool convex = false) { triangles = null; int vertexCount = vertices == null ? 0 : vertices.Length; if (vertexCount < 3) return false; if (vertexCount == 3) { triangles = new List() { 0, 1, 2 }; return true; } Vector3 normal = Projection.FindBestPlane(vertices).normal; Vector2[] points2d = Projection.PlanarProject(vertices); if (unordered) return Triangulation.SortAndTriangulate(points2d, out triangles, convex); else return Triangulate(points2d, out triangles, convex); } /// /// Given a set of points ordered counter-clockwise along a contour, return triangle indexes. /// /// /// /// Triangulation may optionally be set to convex, which will result in some a convex shape. /// public static bool Triangulate(IList points, out List indexes, bool convex = false) { indexes = new List(); int index = 0; Triangulatable soup = convex ? new PointSet(points.Select(x => new TriangulationPoint(x.x, x.y, index++)).ToList()) : (Triangulatable) new Polygon(points.Select(x => new PolygonPoint(x.x, x.y, index++))); try { P2T.Triangulate(TriangulationAlgorithm.DTSweep, soup); } catch (System.Exception e) { Log.Warning("Triangulation failed: " + e.ToString()); return false; } foreach (DelaunayTriangle d in soup.Triangles) { if (d.Points[0].Index < 0 || d.Points[1].Index < 0 || d.Points[2].Index < 0) { Log.Warning("Triangulation failed: Additional vertices were inserted."); return false; } indexes.Add(d.Points[0].Index); indexes.Add(d.Points[1].Index); indexes.Add(d.Points[2].Index); } WindingOrder originalWinding = SurfaceTopology.GetWindingOrder(points); // if the re-triangulated first tri doesn't match the winding order of the original // vertices, flip 'em if (SurfaceTopology.GetWindingOrder(new Vector2[3] { points[indexes[0]], points[indexes[1]], points[indexes[2]], }) != originalWinding) indexes.Reverse(); return true; } } }