public static bool SplitPolygonsByPlane(List <Polygon> polygons, // Source polygons that will be split Plane splitPlane, bool excludeNewPolygons, // Whether new polygons should be marked as excludeFromBuild out List <Polygon> polygonsFront, out List <Polygon> polygonsBack) { polygonsFront = new List <Polygon>(); polygonsBack = new List <Polygon>(); // First of all make sure splitting actually needs to occur (we'll get bad issues if // we try splitting geometry when we don't need to) if (!PolygonsIntersectPlane(polygons, splitPlane)) { return(false); } Material newMaterial = polygons[0].Material; // These are the vertices that will be used in the new caps List <Vertex> newVertices = new List <Vertex>(); for (int polygonIndex = 0; polygonIndex < polygons.Count; polygonIndex++) { Polygon.PolygonPlaneRelation planeRelation = Polygon.TestPolygonAgainstPlane(polygons[polygonIndex], splitPlane); // Polygon has been found to span both sides of the plane, attempt to split into two pieces if (planeRelation == Polygon.PolygonPlaneRelation.Spanning) { Polygon frontPolygon; Polygon backPolygon; Vertex newVertex1; Vertex newVertex2; // Attempt to split the polygon if (Polygon.SplitPolygon(polygons[polygonIndex], out frontPolygon, out backPolygon, out newVertex1, out newVertex2, splitPlane)) { // If the split algorithm was successful (produced two valid polygons) then add each polygon to // their respective points and track the intersection points polygonsFront.Add(frontPolygon); polygonsBack.Add(backPolygon); newVertices.Add(newVertex1); newVertices.Add(newVertex2); newMaterial = polygons[polygonIndex].Material; } else { // Two valid polygons weren't generated, so use the valid one if (frontPolygon != null) { planeRelation = Polygon.PolygonPlaneRelation.InFront; } else if (backPolygon != null) { planeRelation = Polygon.PolygonPlaneRelation.Behind; } else { Debug.LogError("Polygon splitting has resulted in two zero area polygons. This is unhandled."); // Polygon.PolygonPlaneRelation secondplaneRelation = Polygon.TestPolygonAgainstPlane(polygons[polygonIndex], splitPlane); } } } // If the polygon is on one side of the plane or the other if (planeRelation != Polygon.PolygonPlaneRelation.Spanning) { // Make sure any points that are coplanar on non-straddling polygons are still used in polygon // construction for (int vertexIndex = 0; vertexIndex < polygons[polygonIndex].Vertices.Length; vertexIndex++) { if (Polygon.ComparePointToPlane(polygons[polygonIndex].Vertices[vertexIndex].Position, splitPlane) == Polygon.PointPlaneRelation.On) { newVertices.Add(polygons[polygonIndex].Vertices[vertexIndex]); } } if (planeRelation == Polygon.PolygonPlaneRelation.Behind) { polygonsBack.Add(polygons[polygonIndex]); } else { polygonsFront.Add(polygons[polygonIndex]); } } } // If any splits occured or coplanar vertices are found. (For example if you're splitting a sphere at the // equator then no polygons will be split but there will be a bunch of coplanar vertices!) if (newVertices.Count > 0) { // HACK: This code is awful, because we end up with lots of duplicate vertices List <Vector3> positions = newVertices.Select(item => item.Position).ToList(); Polygon newPolygon = PolygonFactory.ConstructPolygon(positions, true); // Assuming it was possible to create a polygon if (newPolygon != null) { if (!MathHelper.PlaneEqualsLooser(newPolygon.Plane, splitPlane)) { // Polygons are sometimes constructed facing the wrong way, possibly due to a winding order // mismatch. If the two normals are opposite, flip the new polygon if (Vector3.Dot(newPolygon.Plane.normal, splitPlane.normal) < -0.9f) { newPolygon.Flip(); } } newPolygon.ExcludeFromFinal = excludeNewPolygons; newPolygon.Material = newMaterial; polygonsFront.Add(newPolygon); newPolygon = newPolygon.DeepCopy(); newPolygon.Flip(); newPolygon.ExcludeFromFinal = excludeNewPolygons; newPolygon.Material = newMaterial; if (newPolygon.Plane.normal == Vector3.zero) { Debug.LogError("Invalid Normal! Shouldn't be zero. This is unexpected since extraneous positions should have been removed!"); // Polygon fooNewPolygon = PolygonFactory.ConstructPolygon(positions, true); } polygonsBack.Add(newPolygon); } return(true); } else { // It wasn't possible to create the polygon, for example the constructed polygon was too small // This could happen if you attempt to clip the tip off a long but thin brush, the plane-polyhedron test // would say they intersect but in reality the resulting polygon would be near zero area return(false); } }
internal static bool SplitCoplanarPolygonsByPlane(List <Polygon> polygons, // Source polygons that will be split Plane splitPlane, out List <Polygon> polygonsFront, out List <Polygon> polygonsBack) { polygonsFront = new List <Polygon>(); polygonsBack = new List <Polygon>(); for (int polygonIndex = 0; polygonIndex < polygons.Count; polygonIndex++) { Polygon.PolygonPlaneRelation planeRelation = Polygon.TestPolygonAgainstPlane(polygons[polygonIndex], splitPlane); // Polygon has been found to span both sides of the plane, attempt to split into two pieces if (planeRelation == Polygon.PolygonPlaneRelation.Spanning) { Polygon frontPolygon; Polygon backPolygon; Vertex newVertex1; Vertex newVertex2; // Attempt to split the polygon if (Polygon.SplitPolygon(polygons[polygonIndex], out frontPolygon, out backPolygon, out newVertex1, out newVertex2, splitPlane)) { // If the split algorithm was successful (produced two valid polygons) then add each polygon to // their respective points and track the intersection points polygonsFront.Add(frontPolygon); polygonsBack.Add(backPolygon); } else { // Two valid polygons weren't generated, so use the valid one if (frontPolygon != null) { planeRelation = Polygon.PolygonPlaneRelation.InFront; } else if (backPolygon != null) { planeRelation = Polygon.PolygonPlaneRelation.Behind; } else { planeRelation = Polygon.PolygonPlaneRelation.InFront; Debug.LogError("Polygon splitting has resulted in two zero area polygons. This is unhandled."); // Polygon.PolygonPlaneRelation secondplaneRelation = Polygon.TestPolygonAgainstPlane(polygons[polygonIndex], splitPlane); } } } // If the polygon is on one side of the plane or the other if (planeRelation != Polygon.PolygonPlaneRelation.Spanning) { if (planeRelation == Polygon.PolygonPlaneRelation.Behind) { polygonsBack.Add(polygons[polygonIndex]); } else { polygonsFront.Add(polygons[polygonIndex]); } } } if (polygonsBack.Count >= 1 && polygonsFront.Count >= 1) { return(true); } else { return(false); } }