예제 #1
0
        public static void RemoveDuplicates(List <Vertex> poly)
        {
            for (var i = 0; i < poly.Count; ++i)
            {
                if (poly[i].ApproximatelyEquals(poly[MeshUtils.LoopIndex(i + 1, poly.Count)]))
                {
                    poly.RemoveAt(i--);
                }

                if (poly.Count <= 3)
                {
                    break;
                }
            }
        }
예제 #2
0
        public static List <List <Vertex> > GetEdgeVerticesIgnoreHoles(Mesh mesh, string debugName = null)
        {
            var edgeDict = new Dictionary <Tuple <int, int>, bool>();
            var verts    = mesh.vertices;
            var indices  = mesh.triangles;

            for (var i = 0; i < indices.Length; i += 3)
            {
                for (var j = 0; j < 3; ++j)
                {
                    var index     = indices[i + j];
                    var nextIndex = indices[i + LoopIndex(j + 1, 3)];
                    edgeDict[new Tuple <int, int>(index, nextIndex)] = true;
                }
            }

            for (var i = 0; i < indices.Length; i += 3)
            {
                for (var j = 0; j < 3; ++j)
                {
                    var index     = indices[i + j];
                    var nextIndex = indices[i + LoopIndex(j + 1, 3)];
                    var key       = new Tuple <int, int>(nextIndex, index);
                    if (edgeDict.ContainsKey(key))
                    {
                        edgeDict[key] = false;
                    }
                }
            }

            var result      = new List <List <Vertex> >();
            var newVerts    = new List <Vertex>();
            var usedIndices = new List <int>();

            bool TryFindBestUnusedVertex(out KeyValuePair <Tuple <int, int>, bool> unusedVert)
            {
                var found = false;
                KeyValuePair <Tuple <int, int>, bool> firstKvp;

                foreach (var kvp in edgeDict)
                {
                    if (!kvp.Value || usedIndices.Contains(kvp.Key.Item1))
                    {
                        continue;
                    }

                    var thisVert      = verts[kvp.Key.Item1];
                    var pointIsInside = false;

                    foreach (var finishedPoly in result)
                    {
                        if (IsPointInPolygon(finishedPoly, thisVert))
                        {
                            usedIndices.Add(kvp.Key.Item1);
                            pointIsInside = true;
                            break;
                        }
                    }

                    if (pointIsInside)
                    {
                        continue;
                    }

                    if (!found)
                    {
                        found    = true;
                        firstKvp = kvp;
                        continue;
                    }

                    var firstVert = verts[firstKvp.Key.Item1];

                    if (thisVert.x < firstVert.x || Mathf.Approximately(thisVert.x, firstVert.x) && thisVert.z < firstVert.z)
                    {
                        firstKvp = kvp;
                    }
                }

                unusedVert = found ? firstKvp : default;
                return(found);
            }

            var usedEdges = new List <KeyValuePair <Tuple <int, int>, bool> >();

            while (TryFindBestUnusedVertex(out var bestKvp))
            {
                var firstIndex   = bestKvp.Key.Item1;
                var currentIndex = bestKvp.Key.Item2;
                var iteration    = 0;
                newVerts.Add(new Vertex(verts[currentIndex]));
                usedIndices.Add(currentIndex);

                while (currentIndex != firstIndex)
                {
                    var nextItem = edgeDict.FirstOrDefault(x => x.Value && x.Key.Item1 == currentIndex && !usedEdges.Contains(x));
                    var def      = default(KeyValuePair <Tuple <int, int>, bool>);
                    if (nextItem.Equals(def))
                    {
                        // TODO: zero-surface vertices welded together break this, review
                        var warningMsg = "Unsupported mesh shape found, falling back to convex hull.";
                        if (!string.IsNullOrEmpty(debugName))
                        {
                            warningMsg += $" ({debugName})";
                        }
                        Debug.LogWarning(warningMsg);

                        result.Clear();
                        var allVerts = verts.Select(x => new Vertex(x)).ToList();
                        result.Add(MeshUtils.GetConvexHull(allVerts));
                        return(result);
                    }

                    currentIndex = nextItem.Key.Item2;
                    newVerts.Add(new Vertex(verts[currentIndex]));
                    usedIndices.Add(currentIndex);
                    usedEdges.Add(nextItem);

                    if (++iteration > 65536)
                    {
                        throw new Exception("Infinite loop encountered when looking for external edges.");
                    }
                }

                newVerts.Reverse();
                result.Add(new List <Vertex>(newVerts));
                newVerts.Clear();
            }

            return(result);
        }
예제 #3
0
        public static List <Triangle> TriangulateEarClipping(List <Vertex> vertices, string debugName = null, bool recursiveCall = false)
        {
            var tris             = new List <Triangle>();
            var volatileVertices = new List <Vertex>(vertices);

            if (volatileVertices.Count == 3)
            {
                tris.Add(new Triangle(volatileVertices[0], volatileVertices[1], volatileVertices[2]));
                return(tris);
            }

            for (var i = 0; i < volatileVertices.Count; i++)
            {
                volatileVertices[i].previous = volatileVertices[MeshUtils.LoopIndex(i - 1, volatileVertices.Count)];
                volatileVertices[i].next     = volatileVertices[MeshUtils.LoopIndex(i + 1, volatileVertices.Count)];
            }

            var ears = new List <Vertex>();

            foreach (var vert in volatileVertices)
            {
                MarkIfReflex(vert);
                MeshUtils.AddToListIfEar(vert, volatileVertices, ears);
            }

            while (true)
            {
                if (volatileVertices.Count == 3)
                {
                    tris.Add(new Triangle(volatileVertices[0], volatileVertices[0].previous, volatileVertices[0].next));
                    break;
                }

                var index   = -1;
                var minDist = float.MaxValue;
                for (var i = 0; i < ears.Count; ++i)
                {
                    var point    = ears[i];
                    var d01      = Vector3.Distance(point.Position, point.previous.Position);
                    var d02      = Vector3.Distance(point.Position, point.next.Position);
                    var d12      = Vector3.Distance(point.previous.Position, point.next.Position);
                    var localMax = Mathf.Max(d01, Mathf.Max(d02, d12));

                    if (localMax < minDist)
                    {
                        minDist = localMax;
                        index   = i;
                    }
                }

                if (ears.Count == 0 || index == -1)
                {
                    if (recursiveCall)
                    {
                        var exceptionMsg = "Can't triangulate poly or its convex hull - terminating.";
                        if (!string.IsNullOrEmpty(debugName))
                        {
                            exceptionMsg += $" ({debugName})";
                        }

                        throw new Exception(exceptionMsg);
                    }

                    var warningMsg = "Unsupported mesh shape found, falling back to convex hull.";
                    if (!string.IsNullOrEmpty(debugName))
                    {
                        warningMsg += $" ({debugName})";
                    }

                    Debug.LogWarning(warningMsg);

                    // Poly is invalid - create convex hull and return it instead
                    var hull = MeshUtils.GetConvexHull(vertices);
                    return(hull == null ? null : TriangulateEarClipping(hull, debugName, true));
                }

                var current = ears[index];
                var prev    = current.previous;
                var next    = current.next;

                tris.Add(new Triangle(current, prev, next));

                ears.Remove(current);
                volatileVertices.Remove(current);

                prev.next     = next;
                next.previous = prev;

                MarkIfReflex(prev);
                MarkIfReflex(next);

                ears.Remove(prev);
                ears.Remove(next);

                MeshUtils.AddToListIfEar(prev, volatileVertices, ears);
                MeshUtils.AddToListIfEar(next, volatileVertices, ears);
            }

            return(tris);
        }
예제 #4
0
 private static void MarkIfReflex(Vertex v)
 {
     v.isReflex = MeshUtils.IsTriangleClockwise(v.previous, v, v.next);
 }