// Slice mesh along plane intersection public static void SliceMesh(GameObject obj, CustomPlane plane, bool isConvex) { // original GameObject data Transform objTransform = obj.transform; Mesh objMesh = obj.GetComponent<MeshFilter>().mesh; Vector3[] meshVerts = objMesh.vertices; int[] meshTris = objMesh.triangles; Vector2[] meshUVs = objMesh.uv; // Slice mesh data slice1Verts = new List<Vector3>(); slice2Verts = new List<Vector3>(); slice1Tris = new List<int>(); slice2Tris = new List<int>(); slice1UVs = new List<Vector2>(); slice2UVs = new List<Vector2>(); lineLoop = new List<Line>(); // Loop through triangles for(int i = 0; i < meshTris.Length / 3; i++) { // Define triangle Vector3[] triVertsLocal = new Vector3[3]; Vector3[] triVertsWorld = new Vector3[3]; Vector2[] triUVs = new Vector2[3]; for(int j = 0; j < 3; j++) { int meshIndexor = (i + 1) * 3 - (3 - j); triVertsLocal[j] = meshVerts[meshTris[meshIndexor]]; // local model space vertices triVertsWorld[j] = objTransform.TransformPoint(triVertsLocal[j]); // world space vertices triUVs[j] = meshUVs[meshTris[meshIndexor]]; // original uv coordinates } // Side test: (0) = intersecting plane; (+) = above plane; (-) = below plane; float vert1Side = plane.GetSide(triVertsWorld[0]); float vert2Side = plane.GetSide(triVertsWorld[1]); float vert3Side = plane.GetSide(triVertsWorld[2]); // assign triangles that do not intersect plane if(vert1Side > 0 && vert2Side > 0 && vert3Side > 0) { // Slice 1 for(int j = 0; j < triVertsLocal.Length; j++) { slice1Verts.Add(triVertsLocal[j]); slice1Tris.Add(slice1Verts.Count - 1); slice1UVs.Add(triUVs[j]); } } else if(vert1Side < 0 && vert2Side < 0 && vert3Side < 0) { // Slice 2 for(int j = 0; j < triVertsLocal.Length; j++) { slice2Verts.Add(triVertsLocal[j]); slice2Tris.Add(slice2Verts.Count - 1); slice2UVs.Add(triUVs[j]); } } else if(vert1Side == 0 || vert2Side == 0 || vert3Side == 0) { Debug.Log ("Point-Plane Intersection"); return; } else { // Intersecting Triangles Vector3[] slicedTriVerts = new Vector3[5]; Vector2[] slicedTriUVs = new Vector2[5]; Vector3[] triVertsWorld2 = new Vector3[3]; int[] vertOrder; // triangle vertex-order CW vs. CCW if(vert1Side * vert2Side > 0) { int[] triOrder = {2,0,1}; for(int j = 0; j < triOrder.Length; j++) { slicedTriVerts[j] = triVertsLocal[triOrder[j]]; slicedTriUVs[j] = triUVs[triOrder[j]]; triVertsWorld2[j] = triVertsWorld[triOrder[j]]; } vertOrder = vertOrderCW; } else if(vert1Side * vert3Side > 0) { int[] triOrder = {1,0,2}; for(int j = 0; j < triOrder.Length; j++) { slicedTriVerts[j] = triVertsLocal[triOrder[j]]; slicedTriUVs[j] = triUVs[triOrder[j]]; triVertsWorld2[j] = triVertsWorld[triOrder[j]]; } vertOrder = vertOrderCCW; } else { int[] triOrder = {0,1,2}; for(int j = 0; j < triOrder.Length; j++) { slicedTriVerts[j] = triVertsLocal[triOrder[j]]; slicedTriUVs[j] = triUVs[triOrder[j]]; triVertsWorld2[j] = triVertsWorld[triOrder[j]]; } vertOrder = vertOrderCW; } // Points of Intersection Vector3 poi1 = plane.VectorPlanePOI(triVertsWorld2[0], (triVertsWorld2[1] - triVertsWorld2[0]).normalized); Vector3 poi2 = plane.VectorPlanePOI(triVertsWorld2[0], (triVertsWorld2[2] - triVertsWorld2[0]).normalized); slicedTriVerts[3] = objTransform.InverseTransformPoint(poi1); slicedTriVerts[4] = objTransform.InverseTransformPoint(poi2); lineLoop.Add(new Line(slicedTriVerts[3], slicedTriVerts[4], poi1, poi2)); // POI UVs float t1 = Vector3.Distance(slicedTriVerts[0], slicedTriVerts[3]) / Vector3.Distance(slicedTriVerts[0], slicedTriVerts[1]); float t2 = Vector3.Distance(slicedTriVerts[0], slicedTriVerts[4]) / Vector3.Distance(slicedTriVerts[0], slicedTriVerts[2]); slicedTriUVs[3] = Vector2.Lerp(slicedTriUVs[0], slicedTriUVs[1], t1); slicedTriUVs[4] = Vector2.Lerp(slicedTriUVs[0], slicedTriUVs[2], t2); // Add bisected triangle to slice respectively if(plane.GetSide(triVertsWorld2[0]) > 0) { // Slice 1 for(int j = 0; j < 3; j++) { slice1Verts.Add(slicedTriVerts[vertOrder[j]]); slice1Tris.Add(slice1Verts.Count - 1); slice1UVs.Add(slicedTriUVs[vertOrder[j]]); } // Slice 2 for(int j = 3; j < 9; j++) { slice2Verts.Add(slicedTriVerts[vertOrder[j]]); slice2Tris.Add(slice2Verts.Count - 1); slice2UVs.Add(slicedTriUVs[vertOrder[j]]); } } else { // Slice 2 for(int j = 0; j < 3; j++) { slice2Verts.Add(slicedTriVerts[vertOrder[j]]); slice2Tris.Add(slice2Verts.Count - 1); slice2UVs.Add(slicedTriUVs[vertOrder[j]]); } // Slice 1 for(int j = 3; j < 9; j++) { slice1Verts.Add(slicedTriVerts[vertOrder[j]]); slice1Tris.Add(slice1Verts.Count - 1); slice1UVs.Add(slicedTriUVs[vertOrder[j]]); } } } } if(lineLoop.Count > 0) { // Fill convex mesh if(isConvex) { Vector3 normal = plane.normal; do { Polygon polygon = new Polygon(lineLoop, normal); Vector3 polygonNormal = (polygon.isClockWise) ? normal : -normal; TriangulatePolygon(polygon.edges, polygonNormal, polygon.isClockWise); } while(lineLoop.Count != 0); } // Build Meshes if(slice1Verts.Count > 0) { BuildSlice(obj, objTransform, slice1Verts.ToArray(), slice1Tris.ToArray(), slice1UVs.ToArray()); } if(slice2Verts.Count > 0) { BuildSlice(obj, objTransform, slice2Verts.ToArray(), slice2Tris.ToArray(), slice2UVs.ToArray()); } // Delete original GameObject.Destroy(obj); } }
// Slice mesh along plane intersection public static void SliceMesh(GameObject obj, CustomPlane plane, bool isConvex) { // original GameObject data Transform objTransform = obj.transform; Mesh objMesh = obj.GetComponent <MeshFilter>().mesh; Vector3[] meshVerts = objMesh.vertices; int[] meshTris = objMesh.triangles; Vector2[] meshUVs = objMesh.uv; // Slice mesh data slice1Verts = new List <Vector3>(); slice2Verts = new List <Vector3>(); slice1Tris = new List <int>(); slice2Tris = new List <int>(); slice1UVs = new List <Vector2>(); slice2UVs = new List <Vector2>(); lineLoop = new List <Line>(); // Loop through triangles for (int i = 0; i < meshTris.Length / 3; i++) { // Define triangle Vector3[] triVertsLocal = new Vector3[3]; Vector3[] triVertsWorld = new Vector3[3]; Vector2[] triUVs = new Vector2[3]; for (int j = 0; j < 3; j++) { int meshIndexor = (i + 1) * 3 - (3 - j); triVertsLocal[j] = meshVerts[meshTris[meshIndexor]]; // local model space vertices triVertsWorld[j] = objTransform.TransformPoint(triVertsLocal[j]); // world space vertices triUVs[j] = meshUVs[meshTris[meshIndexor]]; // original uv coordinates } // Side test: (0) = intersecting plane; (+) = above plane; (-) = below plane; float vert1Side = plane.GetSide(triVertsWorld[0]); float vert2Side = plane.GetSide(triVertsWorld[1]); float vert3Side = plane.GetSide(triVertsWorld[2]); // assign triangles that do not intersect plane if (vert1Side > 0 && vert2Side > 0 && vert3Side > 0) // Slice 1 { for (int j = 0; j < triVertsLocal.Length; j++) { slice1Verts.Add(triVertsLocal[j]); slice1Tris.Add(slice1Verts.Count - 1); slice1UVs.Add(triUVs[j]); } } else if (vert1Side < 0 && vert2Side < 0 && vert3Side < 0) // Slice 2 { for (int j = 0; j < triVertsLocal.Length; j++) { slice2Verts.Add(triVertsLocal[j]); slice2Tris.Add(slice2Verts.Count - 1); slice2UVs.Add(triUVs[j]); } } else if (vert1Side == 0 || vert2Side == 0 || vert3Side == 0) { Debug.Log("Point-Plane Intersection"); return; } else // Intersecting Triangles { Vector3[] slicedTriVerts = new Vector3[5]; Vector2[] slicedTriUVs = new Vector2[5]; Vector3[] triVertsWorld2 = new Vector3[3]; int[] vertOrder; // triangle vertex-order CW vs. CCW if (vert1Side * vert2Side > 0) { int[] triOrder = { 2, 0, 1 }; for (int j = 0; j < triOrder.Length; j++) { slicedTriVerts[j] = triVertsLocal[triOrder[j]]; slicedTriUVs[j] = triUVs[triOrder[j]]; triVertsWorld2[j] = triVertsWorld[triOrder[j]]; } vertOrder = vertOrderCW; } else if (vert1Side * vert3Side > 0) { int[] triOrder = { 1, 0, 2 }; for (int j = 0; j < triOrder.Length; j++) { slicedTriVerts[j] = triVertsLocal[triOrder[j]]; slicedTriUVs[j] = triUVs[triOrder[j]]; triVertsWorld2[j] = triVertsWorld[triOrder[j]]; } vertOrder = vertOrderCCW; } else { int[] triOrder = { 0, 1, 2 }; for (int j = 0; j < triOrder.Length; j++) { slicedTriVerts[j] = triVertsLocal[triOrder[j]]; slicedTriUVs[j] = triUVs[triOrder[j]]; triVertsWorld2[j] = triVertsWorld[triOrder[j]]; } vertOrder = vertOrderCW; } // Points of Intersection Vector3 poi1 = plane.VectorPlanePOI(triVertsWorld2[0], (triVertsWorld2[1] - triVertsWorld2[0]).normalized); Vector3 poi2 = plane.VectorPlanePOI(triVertsWorld2[0], (triVertsWorld2[2] - triVertsWorld2[0]).normalized); slicedTriVerts[3] = objTransform.InverseTransformPoint(poi1); slicedTriVerts[4] = objTransform.InverseTransformPoint(poi2); lineLoop.Add(new Line(slicedTriVerts[3], slicedTriVerts[4], poi1, poi2)); // POI UVs float t1 = Vector3.Distance(slicedTriVerts[0], slicedTriVerts[3]) / Vector3.Distance(slicedTriVerts[0], slicedTriVerts[1]); float t2 = Vector3.Distance(slicedTriVerts[0], slicedTriVerts[4]) / Vector3.Distance(slicedTriVerts[0], slicedTriVerts[2]); slicedTriUVs[3] = Vector2.Lerp(slicedTriUVs[0], slicedTriUVs[1], t1); slicedTriUVs[4] = Vector2.Lerp(slicedTriUVs[0], slicedTriUVs[2], t2); // Add bisected triangle to slice respectively if (plane.GetSide(triVertsWorld2[0]) > 0) { // Slice 1 for (int j = 0; j < 3; j++) { slice1Verts.Add(slicedTriVerts[vertOrder[j]]); slice1Tris.Add(slice1Verts.Count - 1); slice1UVs.Add(slicedTriUVs[vertOrder[j]]); } // Slice 2 for (int j = 3; j < 9; j++) { slice2Verts.Add(slicedTriVerts[vertOrder[j]]); slice2Tris.Add(slice2Verts.Count - 1); slice2UVs.Add(slicedTriUVs[vertOrder[j]]); } } else { // Slice 2 for (int j = 0; j < 3; j++) { slice2Verts.Add(slicedTriVerts[vertOrder[j]]); slice2Tris.Add(slice2Verts.Count - 1); slice2UVs.Add(slicedTriUVs[vertOrder[j]]); } // Slice 1 for (int j = 3; j < 9; j++) { slice1Verts.Add(slicedTriVerts[vertOrder[j]]); slice1Tris.Add(slice1Verts.Count - 1); slice1UVs.Add(slicedTriUVs[vertOrder[j]]); } } } } if (lineLoop.Count > 0) { // Fill convex mesh if (isConvex) { Vector3 normal = plane.normal; do { Polygon polygon = new Polygon(lineLoop, normal); Vector3 polygonNormal = (polygon.isClockWise) ? normal : -normal; TriangulatePolygon(polygon.edges, polygonNormal, polygon.isClockWise); } while(lineLoop.Count != 0); } // Build Meshes if (slice1Verts.Count > 0) { BuildSlice(obj, objTransform, slice1Verts.ToArray(), slice1Tris.ToArray(), slice1UVs.ToArray()); } if (slice2Verts.Count > 0) { BuildSlice(obj, objTransform, slice2Verts.ToArray(), slice2Tris.ToArray(), slice2UVs.ToArray()); } // Delete original GameObject.Destroy(obj); } }