public static TriangulatedMesh Add(Vector3 position, Vector2[] points, List <Triangulation.IntTriple> connections, Material meshMat = null, bool attachRigidbody = true)
        {
            GameObject triangulatedMesh = new GameObject();

            triangulatedMesh.transform.position = MeshHelper.GetCenter(points);

            TriangulatedMesh triComponent = triangulatedMesh.AddComponent <TriangulatedMesh>();

            triComponent.Build(points, connections, meshMat);
            if (attachRigidbody)
            {
                triangulatedMesh.AddComponent <Rigidbody2D>();
            }
            return(triComponent);
        }
        public static GearMesh AddGear(Vector3 position, float innerRadius, float rootRadius, float outerRadius, int sides, Material meshMat = null, bool attachRigidbody = true)
        {
            MeshHelper.SetupMaterial(ref meshMat);
            GameObject gear = new GameObject();

            gear.transform.position = position;

            GearMesh gearComponent = gear.AddComponent <GearMesh>();

            gearComponent.Build(innerRadius, rootRadius, outerRadius, sides, meshMat);
            if (attachRigidbody)
            {
                gear.AddComponent <Rigidbody2D>();
            }
            return(gearComponent);
        }
예제 #3
0
        protected override void BuildMeshComponents()
        {
            BaseVertices = ConvexVertices;

            Vertices = MeshHelper.ConvertVec2ToVec3(ConvexHull.QuickHull(MeshHelper.ConvertVec3ToVec2(ConvexVertices)).ToArray()); // oh no

            Triangles = new int[Vertices.Length * 3];

            for (int i = 1; i < Vertices.Length - 1; i++)
            {
                Triangles[i * 3 + 0] = 0;
                Triangles[i * 3 + 1] = i;
                Triangles[i * 3 + 2] = i + 1;
            }
            UVs = MeshHelper.UVUnwrap(Vertices);
        }
        protected override bool ValidateMesh()
        {
            if (P1 == P2 || P2 == P3 || P3 == P1)
            {
                Debug.LogWarning("TriangleMesh::ValidateMesh: some of the points are identity!");
                return(false);
            }

            int sign = MeshHelper.GetSide(P2, P1, P3);

            if (sign == 0)
            {
                Debug.LogWarning("TriangleMesh::ValidateMesh: Given points are colinear!");
                return(false);
            }

            return(true);
        }
        protected override void BuildMeshComponents()
        {
            Vertices  = new Vector3[sides + 1];
            Triangles = new int[3 * sides];

            float angleDelta = deg360 / sides;

            Vertices[0] = shift;
            for (int i = 1; i < sides + 1; i++)
            {
                Vector3 vertPos = new Vector3(Mathf.Cos(i * angleDelta), Mathf.Sin(i * angleDelta)) * radius;
                Vertices[i] = vertPos;
                Triangles[(i - 1) * 3 + 0] = (1 + i % sides);
                Triangles[(i - 1) * 3 + 1] = 1 + (i - 1) % sides;
                Triangles[(i - 1) * 3 + 2] = 0;
            }
            UVs = MeshHelper.UVUnwrap(Vertices);
        }
예제 #6
0
        protected override bool ValidateMesh()
        {
            if (p1 == p2 || p2 == p3 || p3 == p1)
            {
                Debug.LogWarning("TriangleMesh::ValidateMesh: some of the points are identity!");
                return(false);
            }

            int sign = MeshHelper.GetSide(p2, p1, p3);

            if (sign == 0)
            {
                Debug.LogWarning("TriangleMesh::ValidateMesh: Given points are colinear!");
                return(false);
            }

            return(true);
        }
        protected override void BuildMeshComponents()
        {
            Vector2 center = MeshHelper.GetCenter(Vertices);

            Vertices = new Vector3[Points.Length];
            for (int i = 0; i < Vertices.Length; i++)
            {
                Vertices[i] = Points[i] - center;
            }

            Triangles = new int[Connections.Count * 3];
            for (int i = 0; i < Connections.Count; i++)
            {
                Triangles[i * 3 + 0] = Connections[i].A;
                Triangles[i * 3 + 1] = Connections[i].B;
                Triangles[i * 3 + 2] = Connections[i].C;
            }
            UVs = MeshHelper.UVUnwrap(Vertices);
        }
예제 #8
0
        protected void BuildMesh(ref Material meshMatt)
        {
            if (!Validate || ValidateMesh())
            {
                MeshHelper.CheckMaterial(ref meshMatt);

                _Mesh = new Mesh();
                GetOrAddComponents();
                C_MR.material = meshMatt;

                BuildMeshComponents();
                UpdateMeshFilter();
                UpdateCollider();
            }
            else
            {
                Debug.LogError("MeshBase::BuildMesh: " + name + " generation failed");
            }
        }
        protected override void BuildMeshComponents()
        {
            bool isCircle = innerRadius == 0;

            Vertices  = new Vector3[isCircle ? sides + 1 : 2 * sides];
            Triangles = new int[isCircle ? 3 * sides : 6 * sides];

            if (isCircle)
            {
                //build ordinary circle
                Vertices[0] = Vector3.zero;
                float angleDelta = deg360 / sides;
                for (int i = 1; i < sides + 1; i++)
                {
                    Vector3 vertPos = new Vector3(Mathf.Cos(i * angleDelta), Mathf.Sin(i * angleDelta)) * outerRadius;
                    Vertices[i] = vertPos;
                    Triangles[(i - 1) * 3 + 0] = 0;
                    Triangles[(i - 1) * 3 + 1] = 1 + (i - 1) % sides;
                    Triangles[(i - 1) * 3 + 2] = 1 + i % sides;
                }
            }
            else
            {
                //build a ring!
                float angleDelta    = deg360 / sides;
                int   triangleIndex = 0;
                for (int i = 0; i < sides; i++)
                {
                    Vector3 vertPosInner = new Vector3(Mathf.Cos(i * angleDelta), Mathf.Sin(i * angleDelta)) * innerRadius;
                    Vector3 vertPosOuter = new Vector3(Mathf.Cos(i * angleDelta), Mathf.Sin(i * angleDelta)) * outerRadius;
                    Vertices[i]                = vertPosInner;
                    Vertices[i + sides]        = vertPosOuter;
                    Triangles[triangleIndex++] = i;
                    Triangles[triangleIndex++] = (i + 1) % (sides);
                    Triangles[triangleIndex++] = (i + sides);
                    Triangles[triangleIndex++] = (i + 1) % (sides * 2);
                    Triangles[triangleIndex++] = (i + sides);
                    Triangles[triangleIndex++] = (i + sides + 1) % (sides * 2);
                }
            }
            UVs = MeshHelper.UVUnwrap(Vertices);
        }
예제 #10
0
        public static TriangulatedMesh ConvertToTriangulatedMesh(TriangulableMesh sourceMeshScript)
        {
            //check if mesh is already a triangulated one
            if (sourceMeshScript.GetType() == triangulatedMeshType)
            {
                return(sourceMeshScript.GetComponent <TriangulatedMesh>());
            }

            Object.DestroyImmediate(sourceMeshScript.GetComponent <Collider2D>());
            TriangulatedMesh triangulatedMesh = sourceMeshScript.gameObject.AddComponent <TriangulatedMesh>();

            Vector2[] points = MeshHelper.ConvertVec3ToVec2(sourceMeshScript.GetTriangulableVertices());
            List <Triangulation.IntTriple> connections = Triangulation.TriangulationToInt3(new List <Vector2>(points));

            triangulatedMesh.Build(points, connections, sourceMeshScript.C_MR.sharedMaterial);

            //delete base component
            Object.DestroyImmediate(sourceMeshScript);

            return(triangulatedMesh);
        }
예제 #11
0
        protected override void BuildMeshComponents()
        {
            Vertices  = new Vector3[1 + sides * 2];
            Triangles = new int[2 * sides * 3];
            UVs       = new Vector2[1 + sides * 2];

            Vertices[0] = new Vector3(0, 0);
            float angleDelta = 360 / (float)sides / 2 * Mathf.Deg2Rad;
            float angleShift = -360f / (sides * 4) * Mathf.Deg2Rad;

            for (int i = 0; i < sides * 2; i++)
            {
                Vector3 vertVec = new Vector3(Mathf.Cos(i * angleDelta + angleShift), Mathf.Sin(i * angleDelta + angleShift));
                Vertices[1 + i] = vertVec * (i % 2 == 0 ? radiusA : radiusB);
                Triangles[(i * 3 + 2) % Triangles.Length] = 0;
                Triangles[(i * 3 + 1) % Triangles.Length] = 1 + i % (sides * 2);
                Triangles[i * 3] = 1 + (i + 1) % (sides * 2);
            }

            UVs = MeshHelper.UVUnwrap(Vertices);
        }
        //assign variables, get components and build mesh
        public void Build(float innerRadius, float rootRadius, float outerRadius, int sides, Material meshMat = null)
        {
            MeshHelper.SetupMaterial(ref meshMat);
            name        = "Gear";
            InnerRadius = innerRadius;
            RootRadius  = rootRadius;
            OuterRadius = outerRadius;
            Sides       = sides;

            _Mesh = new Mesh();
            GetOrAddComponents();

            C_MR.material = meshMat;

            if (!Validate || ValidateMesh())
            {
                BuildMeshComponents();
                UpdateMeshFilter();
                UpdateCollider();
            }
        }
예제 #13
0
        public static LineMesh AddLine(Vector3 position, Vector2[] lineVerts, float lineWidth, bool useDoubleCollider, Space space, Material meshMat = null, bool attachRigidbody = true)
        {
            GameObject line = new GameObject();

            if (space == Space.Self)
            {
                line.transform.position = position;
            }
            else
            {
                line.transform.position = position + (Vector3)MeshHelper.GetCenter(lineVerts);
            }

            LineMesh lineComponent = line.AddComponent <LineMesh>();

            lineComponent.Build(lineVerts, lineWidth, useDoubleCollider, meshMat);
            if (attachRigidbody)
            {
                line.AddComponent <Rigidbody2D>();
            }
            return(lineComponent);
        }
예제 #14
0
        public static SplineShapeMesh AddSplineShape(Vector3 position, Vector2[] splinePoints, float resolution = 0.2f, float?minArea = null, Space space = Space.World, Material meshMat = null, bool attachRigidbody = true)
        {
            GameObject splineShapeMesh = new GameObject();

            if (space == Space.Self)
            {
                splineShapeMesh.transform.position = position;
            }
            else
            {
                splineShapeMesh.transform.position = position + (Vector3)MeshHelper.GetCenter(splinePoints);
            }


            SplineShapeMesh splineMeshComponent = splineShapeMesh.AddComponent <SplineShapeMesh>();

            splineMeshComponent.Build(splinePoints, resolution, minArea, meshMat);
            if (attachRigidbody)
            {
                splineShapeMesh.AddComponent <Rigidbody2D>();
            }
            return(splineMeshComponent);
        }
        public static SplineCurveMesh AddSplineCurve(Vector3 position, Vector2[] splinePoints, float resolution, float width, bool useDoubleCollider, float?minArea, Space space, Material meshMat = null, bool attachRigidbody = true)
        {
            GameObject curve = new GameObject();

            if (space == Space.Self)
            {
                curve.transform.position = position;
            }
            else
            {
                curve.transform.position = position + (Vector3)MeshHelper.GetCenter(splinePoints);
            }

            curve.transform.position = position;
            SplineCurveMesh curveComponent = curve.AddComponent <SplineCurveMesh>();

            curveComponent.Build(splinePoints, resolution, width, useDoubleCollider, minArea, meshMat);
            if (attachRigidbody)
            {
                curve.AddComponent <Rigidbody2D>();
            }
            return(curveComponent);
        }
예제 #16
0
        public static bool IsShapeClockWise(List<Vector2> sourcePoints)
        {
            Debug.Assert(sourcePoints.Count>=3, "Triangulation::IsShapeClockwise: points count must be greater than two!");
            double sum = 0;
            for (int i = 0; i < sourcePoints.Count; i++)
            {

                int k1 = i + 1;
                if (k1 >= sourcePoints.Count) k1 -= sourcePoints.Count;

                int k2 = i + 2;
                if (k2 >= sourcePoints.Count) k2 -= sourcePoints.Count;

                if (AreVecsConvex(sourcePoints[i], sourcePoints[k1], sourcePoints[k2]))
                {
                    sum += MeshHelper.AngleBetweenPoints(sourcePoints[i], sourcePoints[k1], sourcePoints[k2]);
                }
                else
                {
                    sum += 360 - MeshHelper.AngleBetweenPoints(sourcePoints[i], sourcePoints[k1], sourcePoints[k2]);
                }
            }
            return System.Math.Round(sum) == 180 * (sourcePoints.Count - 2);
        }
예제 #17
0
        public static List<IntTriple> TriangulationToInt3(List<Vector2> sourcePoints)
        {
            List<IntTriple> triangles = new List<IntTriple>();
            int MAX = sourcePoints.Count * sourcePoints.Count;

            //temporary List of points
            List<VecIndexPair> verts = VecIndexPair.Get(sourcePoints);

            //was shape drew clockwise?
            bool isCW = IsShapeClockWise(sourcePoints);
            int start = 0;

            int repeats = 0;

            while (verts.Count > 2 && repeats < MAX)
            {
                bool earNotFound = true;
                while (earNotFound && repeats < MAX)
                {
                    repeats++;
                    start %= verts.Count;
                    int middle = (start + 1) % verts.Count;
                    int end = (start + 2) % verts.Count;

                    //change the order to fit triangle mesh facing
                    triangles.Add(new IntTriple(verts[start].index, verts[end].index, verts[middle].index));

                    //is current point convex?
                    bool isConvex =
                        IsPointConvex(verts[start].v, verts[middle].v, verts[middle].v, verts[end].v, !isCW)
                        && IsPointConvex(verts[middle].v, verts[end].v, verts[end].v, verts[start].v, !isCW)
                        && IsPointConvex(verts[end].v, verts[start].v, verts[start].v, verts[middle].v, !isCW);

                    if (!isConvex)
                    {
                        //reject the triangle
                        start++;
                        triangles.RemoveAt(triangles.Count - 1);
                        continue;
                    }

                    bool noPointsIn = true;

                    for (int i = 0; i < verts.Count; i++)
                    {
                        if (i != start && i != middle && i != end)
                            if (MeshHelper.IsPointInTriangle(verts[i].v, verts[start].v, verts[middle].v, verts[end].v) && noPointsIn)
                            {
                                //there's a point in triangle
                                noPointsIn = false;
                                //reject the triangle
                                start++;
                                triangles.RemoveAt(triangles.Count - 1);
                                break;
                            }
                    }

                    if (noPointsIn)
                    {
                        earNotFound = false;
                        //add triangle to set
                        verts.RemoveAt(middle);
                    }
                }
            }
            return triangles;
        }
예제 #18
0
 public override void UpdateCollider()
 {
     C_PC2D.points = MeshHelper.ConvertVec3ToVec2(Vertices);
 }
예제 #19
0
        public static List <Vector3> Simplify(List <Vector3> points, float minArea, bool isClosed, bool useCopy = true)
        {
            const int minPointsCount = 10;

            var pts = useCopy ? new List <Vector3>(points) : points;

            if (isClosed)
            {
                int prevPointCount;
                int index = 0;
                do
                {
                    prevPointCount = pts.Count;
                    while (index < pts.Count && pts.Count >= minPointsCount)
                    {
                        Vector2 p1 = pts[index];
                        Vector2 p2 = pts[(index + 1) % pts.Count];
                        Vector2 p3 = pts[(index + 2) % pts.Count];

                        var area = MeshHelper.GetTriangleArea(p1, p2, p3);
                        if (area < minArea)
                        {
                            pts.RemoveAt((index + 1) % pts.Count);
                            index += 2;
                        }
                        else
                        {
                            index++;
                        }
                    }
                    index %= pts.Count;
                } while (prevPointCount != pts.Count);
            }
            else
            {
                int prevPointCount;
                do
                {
                    prevPointCount = pts.Count;
                    int index = 0;
                    while (index < pts.Count - 2 && pts.Count >= minPointsCount)
                    {
                        Vector2 p1 = pts[index];
                        Vector2 p2 = pts[index + 1];
                        Vector2 p3 = pts[index + 2];

                        var area = MeshHelper.GetTriangleArea(p1, p2, p3);
                        if (area < minArea)
                        {
                            pts.RemoveAt(index + 1);
                            index += 2;
                        }
                        else
                        {
                            index++;
                        }
                    }
                } while (prevPointCount != pts.Count);
            }
            return(pts);
        }
예제 #20
0
        public static float BoundingBoxArea(IList <Vector2> splinePoints)
        {
            var bounds = MeshHelper.GetBounds(splinePoints);

            return((bounds.z - bounds.x) * (bounds.w - bounds.y));
        }
예제 #21
0
        protected override void BuildMeshComponents()
        {
            #region DoubleCollider
            if (useDoubleCollider)
            {
                cachedVertsLeft  = new List <Vector2>();
                cachedVertsRight = new List <Vector2>();
            }
            #endregion

            List <Vector3> verticesList  = new List <Vector3>();
            List <int>     trianglesList = new List <int>();

            Vector2 center = new Vector2();
            for (int i = 0; i < lineVerts.Length; i++)
            {
                center += lineVerts[i];
            }
            center /= lineVerts.Length;
            for (int i = 0; i < lineVerts.Length; i++)
            {
                lineVerts[i] -= center;
            }

            int currentVertIndex = 0;
            int currentTriIndex  = 0;
            //add first two vertices
            float   angle = Mathf.Atan2(lineVerts[1].y - lineVerts[0].y, lineVerts[1].x - lineVerts[0].x);
            float   oldAngle, angleDiff;
            Vector2 p1 = new Vector2(Mathf.Cos(angle + deg90), Mathf.Sin(angle + deg90)) * lineWidth;
            Vector2 p2 = new Vector2(Mathf.Cos(angle - deg90), Mathf.Sin(angle - deg90)) * lineWidth;
            if (p1 != p2)
            {
                verticesList.Add(lineVerts[currentVertIndex] + p1);
                verticesList.Add(lineVerts[currentVertIndex] + p2);
                #region DoubleCollider
                if (useDoubleCollider)
                {
                    cachedVertsLeft.Add(verticesList[verticesList.Count - 2]);
                    cachedVertsRight.Add(verticesList[verticesList.Count - 1]);
                }
                #endregion
            }
            else
            {
                verticesList.Add(lineVerts[currentVertIndex]);
                #region DoubleCollider
                if (useDoubleCollider)
                {
                    cachedVertsLeft.Add(verticesList[verticesList.Count - 1]);
                    cachedVertsRight.Add(verticesList[verticesList.Count - 1]);
                }
                #endregion
            }
            oldAngle = angle;
            currentVertIndex++;
            // add middle vertices
            for (int i = 0; i < lineVerts.Length - 2; i++, currentVertIndex++)
            {
                angle     = Mathf.Atan2(lineVerts[currentVertIndex + 1].y - lineVerts[currentVertIndex].y, lineVerts[currentVertIndex + 1].x - lineVerts[currentVertIndex].x);
                angleDiff = oldAngle + MeshHelper.AngleDifference(oldAngle, angle) * 0.5f;
                p1        = new Vector2(Mathf.Cos(angleDiff + deg90), Mathf.Sin(angleDiff + deg90)) * lineWidth;
                p2        = new Vector2(Mathf.Cos(angleDiff - deg90), Mathf.Sin(angleDiff - deg90)) * lineWidth;
                if (p1 != p2)
                {
                    verticesList.Add(lineVerts[currentVertIndex] + p1);
                    verticesList.Add(lineVerts[currentVertIndex] + p2);
                    trianglesList.Add(currentTriIndex + 0);
                    trianglesList.Add(currentTriIndex + 3);
                    trianglesList.Add(currentTriIndex + 1);
                    trianglesList.Add(currentTriIndex + 3);
                    trianglesList.Add(currentTriIndex + 0);
                    trianglesList.Add(currentTriIndex + 2);
                    currentTriIndex += 2;
                }
                else
                {
                    verticesList.Add(lineVerts[currentTriIndex] + p1);
                    if (verticesList[verticesList.Count - 1] != verticesList[verticesList.Count - 2])
                    {
                        trianglesList.Add(currentTriIndex + 0);
                        trianglesList.Add(currentTriIndex + 3);
                        trianglesList.Add(currentTriIndex + 1);
                        currentTriIndex++;
                    }
                }
                #region DoubleCollider
                if (useDoubleCollider)
                {
                    cachedVertsLeft.Add(verticesList[verticesList.Count - 2]);
                    cachedVertsRight.Add(verticesList[verticesList.Count - 1]);
                }
                #endregion
                oldAngle = angle;
            }

            //add last two vertices
            if (lineVerts[0] != lineVerts[currentVertIndex])
            {
                angle = Mathf.Atan2(lineVerts[currentVertIndex].y - lineVerts[currentVertIndex - 1].y, lineVerts[currentVertIndex].x - lineVerts[currentVertIndex - 1].x);
                p1    = new Vector2(Mathf.Cos(angle + deg90), Mathf.Sin(angle + deg90)) * lineWidth;
                p2    = new Vector2(Mathf.Cos(angle - deg90), Mathf.Sin(angle - deg90)) * lineWidth;
                if (p1 != p2)
                {
                    verticesList.Add(lineVerts[currentVertIndex] + p1);
                    verticesList.Add(lineVerts[currentVertIndex] + p2);
                    trianglesList.Add(currentTriIndex + 0);
                    trianglesList.Add(currentTriIndex + 3);
                    trianglesList.Add(currentTriIndex + 1);
                    trianglesList.Add(currentTriIndex + 3);
                    trianglesList.Add(currentTriIndex + 0);
                    trianglesList.Add(currentTriIndex + 2);
                }
                else
                {
                    //make LineMesh loop
                    if (verticesList[verticesList.Count - 1] != verticesList[verticesList.Count - 2])
                    {
                        verticesList.Add(lineVerts[currentTriIndex] + p1);
                        trianglesList.Add(currentTriIndex + 0);
                        trianglesList.Add(currentTriIndex + 3);
                        trianglesList.Add(currentTriIndex + 1);
                    }
                }
                #region DoubleCollider
                if (useDoubleCollider)
                {
                    cachedVertsLeft.Add(verticesList[verticesList.Count - 2]);
                    cachedVertsRight.Add(verticesList[verticesList.Count - 1]);
                }
                #endregion
            }
            else
            {
                oldAngle = Mathf.Atan2(
                    lineVerts[0].y - lineVerts[currentVertIndex].y,
                    lineVerts[0].x - lineVerts[currentVertIndex].x);
                angle = Mathf.Atan2(
                    lineVerts[1].y - lineVerts[0].y,
                    lineVerts[1].x - lineVerts[0].x);
                angleDiff       = oldAngle + MeshHelper.AngleDifference(oldAngle, angle) * 0.5f - deg90;
                p1              = new Vector2(Mathf.Cos(angleDiff - deg90), Mathf.Sin(angleDiff - deg90)) * lineWidth;
                p2              = new Vector2(Mathf.Cos(angleDiff + deg90), Mathf.Sin(angleDiff + deg90)) * lineWidth;
                verticesList[0] = lineVerts[currentVertIndex] + p1;
                verticesList[1] = lineVerts[currentVertIndex] + p2;
                #region DoubleCollider
                if (useDoubleCollider)
                {
                    cachedVertsLeft[0]  = verticesList[0];
                    cachedVertsRight[0] = verticesList[1];
                    cachedVertsLeft.Add(verticesList[verticesList.Count - 2]);
                    cachedVertsRight.Add(verticesList[verticesList.Count - 1]);
                }
                #endregion

                trianglesList.Add(0);
                trianglesList.Add(verticesList.Count - 1);
                trianglesList.Add(1);
                trianglesList.Add(verticesList.Count - 1);
                trianglesList.Add(0);
                trianglesList.Add(verticesList.Count - 2);
            }
            Vertices  = verticesList.ToArray();
            Triangles = trianglesList.ToArray();

            UVs = MeshHelper.UVUnwrap(Vertices);
        }
 //convert to quad
 public QuadrangleMesh ToQuad(bool attachRigidbody = true)
 {
     return(QuadrangleMesh.AddQuadrangle(transform.position, MeshHelper.ConvertVec3ToVec2(Vertices), Space.World, C_MR.material, attachRigidbody));
 }
예제 #23
0
 public override void UpdateCollider()
 {
     C_PC2D.SetPath(0, MeshHelper.ConvertVec3ToVec2(Vertices));
 }
예제 #24
0
        public static List<Vector2Triple> GetTriangles(List<Vector2> sourcePoints)
        {
            List<Vector2Triple> triangles = new List<Vector2Triple>();
            int MAX = sourcePoints.Count * sourcePoints.Count;

            //temporary List of points
            List<Vector2> verts = sourcePoints;

            //was shape drawn clockwise?
            bool isCW = IsShapeClockWise(verts);
            int start = 0;

            int repeats = 0;

            while (verts.Count > 2 && repeats < MAX)
            {
                bool earNotFound = true;
                while (earNotFound && repeats < MAX)
                {
                    repeats++;
                    start %= verts.Count;
                    int middle = (start + 1) % verts.Count;
                    int end = (start + 2) % verts.Count;

                    triangles.Add(new Vector2Triple(verts[start], verts[middle], verts[end]));
                    //is current point convex?
                    bool isConvex =
                        IsPointConvex(verts[start], verts[middle], verts[middle], verts[end], !isCW)
                        && IsPointConvex(verts[middle], verts[end], verts[end], verts[start], !isCW)
                        && IsPointConvex(verts[end], verts[start], verts[start], verts[middle], !isCW);

                    if (!isConvex)
                    {
                        //reject the triangle
                        start++;
                        triangles.RemoveAt(triangles.Count - 1);
                        continue;
                    }

                    bool noPointsIn = true;

                    for (int i = 0; i < verts.Count; i++)
                        if (i != start && i != middle && i != end)
                            if (MeshHelper.IsPointInTriangle(verts[i], verts[start], verts[middle], verts[end]) && noPointsIn)
                            {
                                //there's a point in triangle
                                noPointsIn = false;
                                //reject the triangle
                                start++;
                                triangles.RemoveAt(triangles.Count - 1);
                                break;
                            }

                    if (noPointsIn)
                    {
                        earNotFound = false;
                        //add triangle to set
                        verts.RemoveAt(middle);
                    }
                }
            }
            return triangles;
        }
        protected override void BuildMeshComponents()
        {
            int doubleSides = 2 * Sides;

            Vertices  = new Vector3[6 * Sides];
            Triangles = new int[6 * 3 * Sides];

            float angleDelta      = deg360 / doubleSides;
            float angleShift      = angleDelta * 0.5f;
            float outerAngleShift = angleDelta * 0.2f;

            int triangleIndex = 0;

            for (int i = 0; i < doubleSides; i++)
            {
                Vector3 innerVertPos =
                    new Vector3(Mathf.Cos(i * angleDelta + angleShift), Mathf.Sin(i * angleDelta + angleShift)) * InnerRadius;
                Vector3 rootVertPos =
                    new Vector3(Mathf.Cos(i * angleDelta + angleShift), Mathf.Sin(i * angleDelta + angleShift)) * RootRadius;
                Vector3 outerVertPos;
                if (i % 2 == 0)
                {
                    outerVertPos =
                        new Vector3(Mathf.Cos(i * angleDelta + angleShift + outerAngleShift), Mathf.Sin(i * angleDelta + angleShift + outerAngleShift)) * OuterRadius;
                }
                else
                {
                    outerVertPos =
                        new Vector3(Mathf.Cos(i * angleDelta + angleShift - outerAngleShift), Mathf.Sin(i * angleDelta + angleShift - outerAngleShift)) * OuterRadius;
                }
                Vertices[i * 3 + 0] = innerVertPos;
                Vertices[i * 3 + 1] = rootVertPos;
                Vertices[i * 3 + 2] = outerVertPos;

                int a = 3 * i;
                int b = 3 * i + 1;
                int c = (3 * (i + 1)) % (3 * doubleSides);
                int d = (3 * (i + 1) + 1) % (3 * doubleSides);
                Triangles[triangleIndex++] = d;
                Triangles[triangleIndex++] = b;
                Triangles[triangleIndex++] = c;
                Triangles[triangleIndex++] = b;
                Triangles[triangleIndex++] = a;
                Triangles[triangleIndex++] = c;

                //add tooth
                if (i % 2 == 0)
                {
                    a = 3 * i + 1;
                    b = 3 * i + 2;
                    c = (3 * (i + 1) + 1) % (3 * doubleSides);
                    d = (3 * (i + 1) + 2) % (3 * doubleSides);
                    Triangles[triangleIndex++] = d;
                    Triangles[triangleIndex++] = b;
                    Triangles[triangleIndex++] = c;
                    Triangles[triangleIndex++] = b;
                    Triangles[triangleIndex++] = a;
                    Triangles[triangleIndex++] = c;
                }
            }
            UVs = MeshHelper.UVUnwrap(Vertices);
        }