/// <summary> /// Splits the game object using an array of planes, instantiating the pieces as new /// game objects (clones of the original) and destroying the original game object when finished. /// </summary> /// <param name="planes"> /// An array of world-space planes with unit-length normals. /// </param> public void Split(Plane[] planes) { if (planes != null && planes.Length > 0 && isIntact && hull != null && !hull.IsEmpty) { UvMapper uvMapper = GetComponent <UvMapper>(); ColorMapper colorMapper = GetComponent <ColorMapper>(); if (sendPreSplitMessage) { SendMessage("PreSplit", planes, SendMessageOptions.DontRequireReceiver); } Vector3[] points, normals; ConvertPlanesToLocalspace(planes, out points, out normals); IList <IHull> newHulls; CreateNewHulls(uvMapper, colorMapper, points, normals, out newHulls); GameObject[] newGameObjects; CreateNewGameObjects(newHulls, out newGameObjects); if (sendPostSplitMessage) { SendMessage("PostSplit", newGameObjects, SendMessageOptions.DontRequireReceiver); } //Destroy(gameObject); gameObject.SetActive(false); generation--; //isIntact = false; } }
protected void CreateNewHulls(UvMapper uvMapper, ColorMapper colorMapper, Vector3[] points, Vector3[] normals, out IList <IHull> newHulls) { newHulls = new List <IHull>(); // Add the starting hull newHulls.Add(hull); for (int j = 0; j < points.Length; j++) { int previousHullCount = newHulls.Count; for (int i = 0; i < previousHullCount; i++) { IHull previousHull = newHulls[0]; // Split the previous hull IHull a, b; previousHull.Split(points[j], normals[j], fillCut, uvMapper, colorMapper, out a, out b); // Update the list newHulls.Remove(previousHull); if (!a.IsEmpty) { newHulls.Add(a); } if (!b.IsEmpty) { newHulls.Add(b); } } } }
protected void FillCutEdges(LegacyHull a, LegacyHull b, IList <Edge> edgesA, IList <Edge> edgesB, Vector3 planeNormal, UvMapper uvMapper) { // Create outline data int outlineEdgeCount = edgesA.Count; Vector3[] outlinePoints = new Vector3[outlineEdgeCount]; int[] outlineEdges = new int[outlineEdgeCount * 2]; int startIndex = 0; for (int i = 0; i < outlineEdgeCount; i++) { int currentIndex = i; int nextIndex = (i + 1) % outlineEdgeCount; Edge current = edgesA[currentIndex]; Edge next = edgesA[nextIndex]; // Set point outlinePoints[i] = current.point0.position; // Set edge outlineEdges[i * 2 + 0] = currentIndex; if (current.point1 == next.point0) { outlineEdges[i * 2 + 1] = nextIndex; } else { outlineEdges[i * 2 + 1] = startIndex; startIndex = nextIndex; } } // Triangulate int[] newEdges, newTriangles, newTriangleEdges; ITriangulator triangulator = new Triangulator(outlinePoints, outlineEdges, planeNormal); triangulator.Fill(out newEdges, out newTriangles, out newTriangleEdges); // Calculate vertex properties Vector3 normalA = -planeNormal; Vector3 normalB = planeNormal; Vector4[] tangentsA, tangentsB; Vector2[] uvsA, uvsB; uvMapper.Map(outlinePoints, planeNormal, out tangentsA, out tangentsB, out uvsA, out uvsB); // Create new vertices int[] verticesA = new int[outlineEdgeCount]; int[] verticesB = new int[outlineEdgeCount]; for (int i = 0; i < outlineEdgeCount; i++) { a.AddVertex(outlinePoints[i], normalA, tangentsA[i], uvsA[i], edgesA[i].point0, out verticesA[i]); b.AddVertex(outlinePoints[i], normalB, tangentsB[i], uvsB[i], edgesB[i].point0, out verticesB[i]); } // Create new edges for (int i = 0; i < newEdges.Length / 2; i++) { int point0 = newEdges[i * 2 + 0]; int point1 = newEdges[i * 2 + 1]; Edge edgeA = new Edge(edgesA[point0].point0, edgesA[point1].point0); Edge edgeB = new Edge(edgesB[point0].point0, edgesB[point1].point0); edgesA.Add(edgeA); edgesB.Add(edgeB); a.edges.Add(edgeA); b.edges.Add(edgeB); } // Create new triangles for (int i = 0; i < newTriangles.Length / 3; i++) { int point0 = newTriangles[i * 3 + 0]; int point1 = newTriangles[i * 3 + 1]; int point2 = newTriangles[i * 3 + 2]; int edge0 = newTriangleEdges[i * 3 + 0]; int edge1 = newTriangleEdges[i * 3 + 1]; int edge2 = newTriangleEdges[i * 3 + 2]; Triangle triangleA = new Triangle(verticesA[point0], verticesA[point2], verticesA[point1], edgesA[point0].point0, edgesA[point2].point0, edgesA[point1].point0, edgesA[edge2], edgesA[edge1], edgesA[edge0]); Triangle triangleB = new Triangle(verticesB[point0], verticesB[point1], verticesB[point2], edgesB[point0].point0, edgesB[point1].point0, edgesB[point2].point0, edgesB[edge0], edgesB[edge1], edgesB[edge2]); a.triangles.Add(triangleA); b.triangles.Add(triangleB); } }
public void Split(Vector3 localPointOnPlane, Vector3 localPlaneNormal, bool fillCut, UvMapper uvMapper, ColorMapper colorMapper, out IHull resultA, out IHull resultB) { lock (key) { if (localPlaneNormal == Vector3.zero) { localPlaneNormal = Vector3.up; } LegacyHull a = new LegacyHull(this); LegacyHull b = new LegacyHull(this); SetIndices(); bool[] pointAbovePlane; AssignPoints(a, b, localPointOnPlane, localPlaneNormal, out pointAbovePlane); int[] oldToNewVertex; AssignVertices(a, b, pointAbovePlane, out oldToNewVertex); bool[] edgeIntersectsPlane; EdgeHit[] edgeHits; AssignEdges(a, b, pointAbovePlane, localPointOnPlane, localPlaneNormal, out edgeIntersectsPlane, out edgeHits); IList <Edge> cutEdgesA, cutEdgesB; AssignTriangles(a, b, pointAbovePlane, edgeIntersectsPlane, edgeHits, oldToNewVertex, out cutEdgesA, out cutEdgesB); if (fillCut) { SortCutEdges(cutEdgesA, cutEdgesB); FillCutEdges(a, b, cutEdgesA, cutEdgesB, localPlaneNormal, uvMapper); } ValidateOutput(a, b, localPlaneNormal); Clear(); // Set output resultA = a; resultB = b; } }
protected void FillCutEdges(FastHull a, FastHull b, IList <Vector3> edges, Vector3 planeNormal, UvMapper uvMapper, ColorMapper colorMapper) { int edgeCount = edges.Count / 2; List <Vector3> points = new List <Vector3>(edgeCount); List <int> outline = new List <int>(edgeCount * 2); int start = 0; for (int current = 0; current < edgeCount; current++) { int next = current + 1; // Find the next edge int nearest = start; float nearestDistance = (edges[current * 2 + 1] - edges[start * 2 + 0]).sqrMagnitude; for (int other = next; other < edgeCount; other++) { float distance = (edges[current * 2 + 1] - edges[other * 2 + 0]).sqrMagnitude; if (distance < nearestDistance) { nearest = other; nearestDistance = distance; } } // Is the current edge the last edge in this edge loop? if (nearest == start && current > start) { int pointStart = points.Count; int pointCounter = pointStart; // Add this edge loop to the triangulation lists for (int edge = start; edge < current; edge++) { points.Add(edges[edge * 2 + 0]); outline.Add(pointCounter++); outline.Add(pointCounter); } points.Add(edges[current * 2 + 0]); outline.Add(pointCounter); outline.Add(pointStart); // Start a new edge loop start = next; } else if (next < edgeCount) { // Move the nearest edge so that it follows the current edge Vector3 n0 = edges[next * 2 + 0]; Vector3 n1 = edges[next * 2 + 1]; edges[next * 2 + 0] = edges[nearest * 2 + 0]; edges[next * 2 + 1] = edges[nearest * 2 + 1]; edges[nearest * 2 + 0] = n0; edges[nearest * 2 + 1] = n1; } } if (points.Count > 0) { // Triangulate the outline int[] newEdges, newTriangles, newTriangleEdges; ITriangulator triangulator = new Triangulator(points, outline, planeNormal); triangulator.Fill(out newEdges, out newTriangles, out newTriangleEdges); // Add the new vertices int offsetA = a.vertices.Count; int offsetB = b.vertices.Count; a.vertices.AddRange(points); b.vertices.AddRange(points); if (normals != null) { Vector3 normalA = -planeNormal; Vector3 normalB = planeNormal; for (int i = 0; i < points.Count; i++) { a.normals.Add(normalA); b.normals.Add(normalB); } } if (colors != null) { Color32[] colorsA, colorsB; colorMapper.Map(points, planeNormal, out colorsA, out colorsB); a.colors.AddRange(colorsA); b.colors.AddRange(colorsB); } if (tangents != null || uvs != null) { Vector4[] tangentsA, tangentsB; Vector2[] uvsA, uvsB; uvMapper.Map(points, planeNormal, out tangentsA, out tangentsB, out uvsA, out uvsB); if (tangents != null) { a.tangents.AddRange(tangentsA); b.tangents.AddRange(tangentsB); } if (uvs != null) { a.uvs.AddRange(uvsA); b.uvs.AddRange(uvsB); } } // Add the new triangles int newTriangleCount = newTriangles.Length / 3; for (int i = 0; i < newTriangleCount; i++) { a.indices.Add(offsetA + newTriangles[i * 3 + 0]); a.indices.Add(offsetA + newTriangles[i * 3 + 2]); a.indices.Add(offsetA + newTriangles[i * 3 + 1]); b.indices.Add(offsetB + newTriangles[i * 3 + 0]); b.indices.Add(offsetB + newTriangles[i * 3 + 1]); b.indices.Add(offsetB + newTriangles[i * 3 + 2]); } } }
public void Split(Vector3 localPointOnPlane, Vector3 localPlaneNormal, bool fillCut, UvMapper uvMapper, ColorMapper colorMapper, out IHull resultA, out IHull resultB) { if (localPlaneNormal == Vector3.zero) { localPlaneNormal = Vector3.up; } FastHull a = new FastHull(this); FastHull b = new FastHull(this); bool[] vertexAbovePlane; int[] oldToNewVertexMap; AssignVertices(a, b, localPointOnPlane, localPlaneNormal, out vertexAbovePlane, out oldToNewVertexMap); IList <Vector3> cutEdges; AssignTriangles(a, b, vertexAbovePlane, oldToNewVertexMap, localPointOnPlane, localPlaneNormal, out cutEdges); if (fillCut) { if (colors != null && colorMapper == null) { Debug.LogWarning("Fill cut failed: A ColorMapper was not provided even though the mesh has a color channel"); } else if ((tangents != null || uvs != null) && uvMapper == null) { Debug.LogWarning("Fill cut failed: A UvMapper was not provided even though the mesh has a tangent/uv channel"); } else { FillCutEdges(a, b, cutEdges, localPlaneNormal, uvMapper, colorMapper); } } ValidateOutput(a, b, localPlaneNormal); // Set output resultA = a; resultB = b; }
protected void CreateNewHulls(UvMapper uvMapper, ColorMapper colorMapper, Vector3[] points, Vector3[] normals, out IList<IHull> newHulls) { newHulls = new List<IHull>(); // Add the starting hull newHulls.Add(hull); for (int j = 0; j < points.Length; j++) { int previousHullCount = newHulls.Count; for (int i = 0; i < previousHullCount; i++) { IHull previousHull = newHulls[0]; // Split the previous hull IHull a, b; previousHull.Split(points[j], normals[j], fillCut, uvMapper, colorMapper, out a, out b); // Update the list newHulls.Remove(previousHull); if (!a.IsEmpty) { newHulls.Add(a); } if (!b.IsEmpty) { newHulls.Add(b); } } } }
protected void FillCutEdges(FastHull a, FastHull b, IList<Vector3> edges, Vector3 planeNormal, UvMapper uvMapper, ColorMapper colorMapper) { int edgeCount = edges.Count / 2; List<Vector3> points = new List<Vector3>(edgeCount); List<int> outline = new List<int>(edgeCount * 2); int start = 0; for (int current = 0; current < edgeCount; current++) { int next = current + 1; // Find the next edge int nearest = start; float nearestDistance = (edges[current * 2 + 1] - edges[start * 2 + 0]).sqrMagnitude; for (int other = next; other < edgeCount; other++) { float distance = (edges[current * 2 + 1] - edges[other * 2 + 0]).sqrMagnitude; if (distance < nearestDistance) { nearest = other; nearestDistance = distance; } } // Is the current edge the last edge in this edge loop? if (nearest == start && current > start) { int pointStart = points.Count; int pointCounter = pointStart; // Add this edge loop to the triangulation lists for (int edge = start; edge < current; edge++) { points.Add(edges[edge * 2 + 0]); outline.Add(pointCounter++); outline.Add(pointCounter); } points.Add(edges[current * 2 + 0]); outline.Add(pointCounter); outline.Add(pointStart); // Start a new edge loop start = next; } else if (next < edgeCount) { // Move the nearest edge so that it follows the current edge Vector3 n0 = edges[next * 2 + 0]; Vector3 n1 = edges[next * 2 + 1]; edges[next * 2 + 0] = edges[nearest * 2 + 0]; edges[next * 2 + 1] = edges[nearest * 2 + 1]; edges[nearest * 2 + 0] = n0; edges[nearest * 2 + 1] = n1; } } if (points.Count > 0) { // Triangulate the outline int[] newEdges, newTriangles, newTriangleEdges; ITriangulator triangulator = new Triangulator(points, outline, planeNormal); triangulator.Fill(out newEdges, out newTriangles, out newTriangleEdges); // Add the new vertices int offsetA = a.vertices.Count; int offsetB = b.vertices.Count; a.vertices.AddRange(points); b.vertices.AddRange(points); if (normals != null) { Vector3 normalA = -planeNormal; Vector3 normalB = planeNormal; for (int i = 0; i < points.Count; i++) { a.normals.Add(normalA); b.normals.Add(normalB); } } if (colors != null) { Color32[] colorsA, colorsB; colorMapper.Map(points, planeNormal, out colorsA, out colorsB); a.colors.AddRange(colorsA); b.colors.AddRange(colorsB); } if (tangents != null || uvs != null) { Vector4[] tangentsA, tangentsB; Vector2[] uvsA, uvsB; uvMapper.Map(points, planeNormal, out tangentsA, out tangentsB, out uvsA, out uvsB); if (tangents != null) { a.tangents.AddRange(tangentsA); b.tangents.AddRange(tangentsB); } if (uvs != null) { a.uvs.AddRange(uvsA); b.uvs.AddRange(uvsB); } } // Add the new triangles int newTriangleCount = newTriangles.Length / 3; for (int i = 0; i < newTriangleCount; i++) { a.indices.Add(offsetA + newTriangles[i * 3 + 0]); a.indices.Add(offsetA + newTriangles[i * 3 + 2]); a.indices.Add(offsetA + newTriangles[i * 3 + 1]); b.indices.Add(offsetB + newTriangles[i * 3 + 0]); b.indices.Add(offsetB + newTriangles[i * 3 + 1]); b.indices.Add(offsetB + newTriangles[i * 3 + 2]); } } }
public void Split(Vector3 localPointOnPlane, Vector3 localPlaneNormal, bool fillCut, UvMapper uvMapper, ColorMapper colorMapper, out IHull resultA, out IHull resultB) { if (localPlaneNormal == Vector3.zero) { localPlaneNormal = Vector3.up; } FastHull a = new FastHull(this); FastHull b = new FastHull(this); bool[] vertexAbovePlane; int[] oldToNewVertexMap; AssignVertices(a, b, localPointOnPlane, localPlaneNormal, out vertexAbovePlane, out oldToNewVertexMap); IList<Vector3> cutEdges; AssignTriangles(a, b, vertexAbovePlane, oldToNewVertexMap, localPointOnPlane, localPlaneNormal, out cutEdges); if (fillCut) { if (colors != null && colorMapper == null) { Debug.LogWarning("Fill cut failed: A ColorMapper was not provided even though the mesh has a color channel"); } else if ((tangents != null || uvs != null) && uvMapper == null) { Debug.LogWarning("Fill cut failed: A UvMapper was not provided even though the mesh has a tangent/uv channel"); } else { FillCutEdges(a, b, cutEdges, localPlaneNormal, uvMapper, colorMapper); } } ValidateOutput(a, b, localPlaneNormal); // Set output resultA = a; resultB = b; }
protected void FillCutEdges(LegacyHull a, LegacyHull b, IList<Edge> edgesA, IList<Edge> edgesB, Vector3 planeNormal, UvMapper uvMapper) { // Create outline data int outlineEdgeCount = edgesA.Count; Vector3[] outlinePoints = new Vector3[outlineEdgeCount]; int[] outlineEdges = new int[outlineEdgeCount * 2]; int startIndex = 0; for (int i = 0; i < outlineEdgeCount; i++) { int currentIndex = i; int nextIndex = (i + 1) % outlineEdgeCount; Edge current = edgesA[currentIndex]; Edge next = edgesA[nextIndex]; // Set point outlinePoints[i] = current.point0.position; // Set edge outlineEdges[i * 2 + 0] = currentIndex; if (current.point1 == next.point0) { outlineEdges[i * 2 + 1] = nextIndex; } else { outlineEdges[i * 2 + 1] = startIndex; startIndex = nextIndex; } } // Triangulate int[] newEdges, newTriangles, newTriangleEdges; ITriangulator triangulator = new Triangulator(outlinePoints, outlineEdges, planeNormal); triangulator.Fill(out newEdges, out newTriangles, out newTriangleEdges); // Calculate vertex properties Vector3 normalA = -planeNormal; Vector3 normalB = planeNormal; Vector4[] tangentsA, tangentsB; Vector2[] uvsA, uvsB; uvMapper.Map(outlinePoints, planeNormal, out tangentsA, out tangentsB, out uvsA, out uvsB); // Create new vertices int[] verticesA = new int[outlineEdgeCount]; int[] verticesB = new int[outlineEdgeCount]; for (int i = 0; i < outlineEdgeCount; i++) { a.AddVertex(outlinePoints[i], normalA, tangentsA[i], uvsA[i], edgesA[i].point0, out verticesA[i]); b.AddVertex(outlinePoints[i], normalB, tangentsB[i], uvsB[i], edgesB[i].point0, out verticesB[i]); } // Create new edges for (int i = 0; i < newEdges.Length / 2; i++) { int point0 = newEdges[i * 2 + 0]; int point1 = newEdges[i * 2 + 1]; Edge edgeA = new Edge(edgesA[point0].point0, edgesA[point1].point0); Edge edgeB = new Edge(edgesB[point0].point0, edgesB[point1].point0); edgesA.Add(edgeA); edgesB.Add(edgeB); a.edges.Add(edgeA); b.edges.Add(edgeB); } // Create new triangles for (int i = 0; i < newTriangles.Length / 3; i++) { int point0 = newTriangles[i * 3 + 0]; int point1 = newTriangles[i * 3 + 1]; int point2 = newTriangles[i * 3 + 2]; int edge0 = newTriangleEdges[i * 3 + 0]; int edge1 = newTriangleEdges[i * 3 + 1]; int edge2 = newTriangleEdges[i * 3 + 2]; Triangle triangleA = new Triangle(verticesA[point0], verticesA[point2], verticesA[point1], edgesA[point0].point0, edgesA[point2].point0, edgesA[point1].point0, edgesA[edge2], edgesA[edge1], edgesA[edge0]); Triangle triangleB = new Triangle(verticesB[point0], verticesB[point1], verticesB[point2], edgesB[point0].point0, edgesB[point1].point0, edgesB[point2].point0, edgesB[edge0], edgesB[edge1], edgesB[edge2]); a.triangles.Add(triangleA); b.triangles.Add(triangleB); } }
public void Split(Vector3 localPointOnPlane, Vector3 localPlaneNormal, bool fillCut, UvMapper uvMapper, ColorMapper colorMapper, out IHull resultA, out IHull resultB) { lock (key) { if (localPlaneNormal == Vector3.zero) { localPlaneNormal = Vector3.up; } LegacyHull a = new LegacyHull(this); LegacyHull b = new LegacyHull(this); SetIndices(); bool[] pointAbovePlane; AssignPoints(a, b, localPointOnPlane, localPlaneNormal, out pointAbovePlane); int[] oldToNewVertex; AssignVertices(a, b, pointAbovePlane, out oldToNewVertex); bool[] edgeIntersectsPlane; EdgeHit[] edgeHits; AssignEdges(a, b, pointAbovePlane, localPointOnPlane, localPlaneNormal, out edgeIntersectsPlane, out edgeHits); IList<Edge> cutEdgesA, cutEdgesB; AssignTriangles(a, b, pointAbovePlane, edgeIntersectsPlane, edgeHits, oldToNewVertex, out cutEdgesA, out cutEdgesB); if (fillCut) { SortCutEdges(cutEdgesA, cutEdgesB); FillCutEdges(a, b, cutEdgesA, cutEdgesB, localPlaneNormal, uvMapper); } ValidateOutput(a, b, localPlaneNormal); Clear(); // Set output resultA = a; resultB = b; } }