/// <summary> /// cut mesh by plane /// </summary> /// <param name="mesh">mesh to cut</param> /// <param name="meshTransform">transformation of the mesh</param> /// <param name="plane">cutting plane</param> /// <param name="triangulateHoles">flag for triangulation of holes</param> /// <param name="crossSectionVertexColor">this color will be assigned to cross section, valid only for vertex color shaders</param> /// <param name="crossUV">uv mapping area for cross section</param> /// <param name="allowOpenMesh">allow cutting of open mesh</param> /// <returns>processing time</returns> public float Cut(Mesh mesh, Transform meshTransform, Math.Plane plane, bool triangulateHoles, bool allowOpenMesh, ref List<CutterMesh> meshes, Color crossSectionVertexColor, Vector4 crossUV) { this.crossSectionVertexColour = crossSectionVertexColor; this.crossSectionUV = crossUV; return Cut(mesh, meshTransform, plane, triangulateHoles, allowOpenMesh, ref meshes); }
void Triangulate(List<Dictionary<int, int>> contours, Math.Plane plane, List<Vector3>[] vertices, List<Vector3>[] normals, List<Vector2>[] uvs, List<Vector4>[] tangents, List<Color32>[] colors, List<int>[] triangles, bool uvCutMesh, bool useTangents, bool useColors, bool useNormals) { if (contours.Count == 0 || contours[0].Count < 3) { // Utils.Log("Contour empty!: "); return; } // prepare plane matrix var m = plane.GetPlaneMatrix(); var mInv = m.inverse; var zShit = 0.0f; var polygons = new List<Polygon>(contours.Count); // construct polygons from contours Polygon highAreaPoly = null; foreach (var ctr in contours) { var polygonPoints = new Vector2[ctr.Count]; var j = 0; foreach (var i in ctr.Values) { var p = mInv*vertices[0][i]; polygonPoints[j++] = p; // save z-coordinate zShit = p.z; } var polygon = new Polygon(polygonPoints); polygons.Add(polygon); if (highAreaPoly == null || Mathf.Abs(highAreaPoly.Area) < Mathf.Abs(polygon.Area)) { highAreaPoly = polygon; } } ExploderUtils.Assert(polygons.Count > 0, "Zero polygons!"); // test for holes if (polygons.Count > 0) { var polyToRemove = new List<Polygon>(); foreach (var polygon in polygons) { if (polygon != highAreaPoly) { if (highAreaPoly.IsPointInside(polygon.Points[0])) { highAreaPoly.AddHole(polygon); polyToRemove.Add(polygon); } } } foreach (var polygon in polyToRemove) { polygons.Remove(polygon); } } var vertCounter0 = vertices[0].Count; var vertCounter1 = vertices[1].Count; foreach (var polygon in polygons) { var indices = polygon.Triangulate(); if (indices == null) { continue; } // get polygon bounding square size var min = Mathf.Min(polygon.Min.x, polygon.Min.y); var max = Mathf.Max(polygon.Max.x, polygon.Max.y); var polygonSize = max - min; // Utils.Log("PolygonSize: " + polygonSize + " " + polygon.Min + " " + polygon.Max); // Utils.Log("Triangulate polygons: " + polygon.Points.Length); foreach (var polyPoint in polygon.Points) { var p = m * new Vector3(polyPoint.x, polyPoint.y, zShit); vertices[0].Add(p); vertices[1].Add(p); if (useNormals) { normals[0].Add(-plane.Normal); normals[1].Add(plane.Normal); } if (uvCutMesh) { var uv0 = new Vector2((polyPoint.x - min)/polygonSize, (polyPoint.y - min)/polygonSize); var uv1 = new Vector2((polyPoint.x - min)/polygonSize, (polyPoint.y - min)/polygonSize); // normalize uv to fit cross-section uv area var areaSizeX = crossSectionUV.z - crossSectionUV.x; var areaSizeY = crossSectionUV.w - crossSectionUV.y; uv0.x = crossSectionUV.x + uv0.x * areaSizeX; uv0.y = crossSectionUV.y + uv0.y * areaSizeY; uv1.x = crossSectionUV.x + uv1.x * areaSizeX; uv1.y = crossSectionUV.y + uv1.y * areaSizeY; uvs[0].Add(uv0); uvs[1].Add(uv1); } else { uvs[0].Add(Vector2.zero); uvs[1].Add(Vector2.zero); } if (useTangents) { // fast and dirty way to create tangents var v0 = plane.Normal; MeshUtils.Swap(ref v0.x, ref v0.y); MeshUtils.Swap(ref v0.y, ref v0.z); Vector4 tangent = Vector3.Cross(plane.Normal, v0); tangent.w = 1.0f; tangents[0].Add(tangent); tangent.w = -1.0f; tangents[1].Add(tangent); } if (useColors) { colors[0].Add(crossSectionVertexColour); colors[1].Add(crossSectionVertexColour); } } var indicesCount = indices.Count; var j = indicesCount - 1; for (int i = 0; i < indicesCount; i++) { triangles[0].Add(vertCounter0 + indices[i]); triangles[1].Add(vertCounter1 + indices[j]); j--; } vertCounter0 += polygon.Points.Length; vertCounter1 += polygon.Points.Length; } }
float Cut(Mesh mesh, Transform meshTransform, Math.Plane plane, bool triangulateHoles, bool allowOpenMesh, ref List<CutterMesh> meshes) { var stopWatch = new Stopwatch(); stopWatch.Start(); #if PROFILING MeasureIt.Begin("CutAllocations"); #endif // cache mesh data var trianglesNum = mesh.triangles.Length; var verticesNum = mesh.vertices.Length; var meshTriangles = mesh.triangles; var meshTangents = mesh.tangents; var meshColors = mesh.colors32; var meshVertices = mesh.vertices; var meshNormals = mesh.normals; var meshUV = mesh.uv; var useMeshTangents = meshTangents != null && meshTangents.Length > 0; var useVertexColors = meshColors != null && meshColors.Length > 0; var useNormals = meshNormals != null && meshNormals.Length > 0; // preallocate buffers AllocateBuffers(trianglesNum, verticesNum, useMeshTangents, useVertexColors); CutterMesh mesh0, mesh1; #if PROFILING MeasureIt.End("CutAllocations"); MeasureIt.Begin("CutCycleFirstPass"); #endif // inverse transform cutting plane plane.InverseTransform(meshTransform); // first pass - find complete triangles on both sides of the plane for (int i = 0; i < trianglesNum; i += 3) { // get triangle points var v0 = meshVertices[meshTriangles[i]]; var v1 = meshVertices[meshTriangles[i + 1]]; var v2 = meshVertices[meshTriangles[i + 2]]; var side0 = plane.GetSideFix(ref v0); var side1 = plane.GetSideFix(ref v1); var side2 = plane.GetSideFix(ref v2); meshVertices[meshTriangles[i]] = v0; meshVertices[meshTriangles[i + 1]] = v1; meshVertices[meshTriangles[i + 2]] = v2; // Utils.Log(plane.Pnt + " " + v0 + " " + v1 + " " + " " + v2); // all points on one side if (side0 == side1 && side1 == side2) { var idx = side0 ? 0 : 1; if (meshTriangles[i] >= triCache.Length) { ExploderUtils.Log("TriCacheError " + meshTriangles[i] + " " + triCache.Length + " " + meshVertices.Length); } if (triCache[meshTriangles[i]] == 0) { triangles[idx].Add(triCounter[idx]); vertices[idx].Add(meshVertices[meshTriangles[i]]); uvs[idx].Add(meshUV[meshTriangles[i]]); if (useNormals) { normals[idx].Add(meshNormals[meshTriangles[i]]); } if (useMeshTangents) { tangents[idx].Add(meshTangents[meshTriangles[i]]); } if (useVertexColors) { vertexColors[idx].Add(meshColors[meshTriangles[i]]); } centroid[idx] += meshVertices[meshTriangles[i]]; triCache[meshTriangles[i]] = triCounter[idx] + 1; triCounter[idx]++; } else { triangles[idx].Add(triCache[meshTriangles[i]] - 1); } if (triCache[meshTriangles[i + 1]] == 0) { triangles[idx].Add(triCounter[idx]); vertices[idx].Add(meshVertices[meshTriangles[i + 1]]); uvs[idx].Add(meshUV[meshTriangles[i + 1]]); if (useNormals) { normals[idx].Add(meshNormals[meshTriangles[i + 1]]); } if (useMeshTangents) { tangents[idx].Add(meshTangents[meshTriangles[i+1]]); } if (useVertexColors) { vertexColors[idx].Add(meshColors[meshTriangles[i+1]]); } centroid[idx] += meshVertices[meshTriangles[i + 1]]; triCache[meshTriangles[i + 1]] = triCounter[idx] + 1; triCounter[idx]++; } else { triangles[idx].Add(triCache[meshTriangles[i + 1]] - 1); } if (triCache[meshTriangles[i + 2]] == 0) { triangles[idx].Add(triCounter[idx]); vertices[idx].Add(meshVertices[meshTriangles[i + 2]]); uvs[idx].Add(meshUV[meshTriangles[i + 2]]); if (useNormals) { normals[idx].Add(meshNormals[meshTriangles[i + 2]]); } if (useMeshTangents) { tangents[idx].Add(meshTangents[meshTriangles[i+2]]); } if (useVertexColors) { vertexColors[idx].Add(meshColors[meshTriangles[i+2]]); } centroid[idx] += meshVertices[meshTriangles[i + 2]]; triCache[meshTriangles[i + 2]] = triCounter[idx] + 1; triCounter[idx]++; } else { triangles[idx].Add(triCache[meshTriangles[i + 2]] - 1); } } else { // intersection triangles add to list and process it in second pass cutTris.Add(i); } } if (vertices[0].Count == 0) { centroid[0] = meshVertices[0]; } else { centroid[0] /= vertices[0].Count; } if (vertices[1].Count == 0) { centroid[1] = meshVertices[1]; } else { centroid[1] /= vertices[1].Count; } #if PROFILING MeasureIt.End("CutCycleFirstPass"); MeasureIt.Begin("CutCycleSecondPass"); #endif mesh0.centroid = centroid[0]; mesh1.centroid = centroid[1]; mesh0.mesh = null; mesh1.mesh = null; if (cutTris.Count < 1) { stopWatch.Stop(); return stopWatch.ElapsedMilliseconds; } AllocateContours(cutTris.Count); // second pass - cut intersecting triangles in half foreach (var cutTri in cutTris) { var triangle = new Triangle { ids = new[] { meshTriangles[cutTri + 0], meshTriangles[cutTri + 1], meshTriangles[cutTri + 2] }, pos = new[] { meshVertices[meshTriangles[cutTri + 0]], meshVertices[meshTriangles[cutTri + 1]], meshVertices[meshTriangles[cutTri + 2]] }, normal = useNormals ? new[] { meshNormals[meshTriangles[cutTri + 0]], meshNormals[meshTriangles[cutTri + 1]], meshNormals[meshTriangles[cutTri + 2]] } : new[] { Vector3.zero, Vector3.zero, Vector3.zero }, uvs = new[] { meshUV[meshTriangles[cutTri + 0]], meshUV[meshTriangles[cutTri + 1]], meshUV[meshTriangles[cutTri + 2]] }, tangents = useMeshTangents ? new[] { meshTangents[meshTriangles[cutTri + 0]], meshTangents[meshTriangles[cutTri + 1]], meshTangents[meshTriangles[cutTri + 2]]} : new []{ Vector4.zero, Vector4.zero, Vector4.zero }, colors = useVertexColors ? new[] { meshColors[meshTriangles[cutTri + 0]], meshColors[meshTriangles[cutTri + 1]], meshColors[meshTriangles[cutTri + 2]] } : new Color32[] { Color.white, Color.white, Color.white }, }; // check points with a plane var side0 = plane.GetSide(triangle.pos[0]); var side1 = plane.GetSide(triangle.pos[1]); var side2 = plane.GetSide(triangle.pos[2]); float t0, t1; Vector3 s0 = Vector3.zero, s1 = Vector3.zero; var idxLeft = side0 ? 0 : 1; var idxRight = 1 - idxLeft; if (side0 == side1) { var a = plane.IntersectSegment(triangle.pos[2], triangle.pos[0], out t0, ref s0); var b = plane.IntersectSegment(triangle.pos[2], triangle.pos[1], out t1, ref s1); ExploderUtils.Assert(a && b, "!!!!!!!!!!!!!!!"); // left side ... 2 triangles var s0Left = AddIntersectionPoint(s0, triangle, triangle.ids[2], triangle.ids[0], cutVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals); var s1Left = AddIntersectionPoint(s1, triangle, triangle.ids[2], triangle.ids[1], cutVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals); var v0Left = AddTrianglePoint(triangle.pos[0], triangle.normal[0], triangle.uvs[0], triangle.tangents[0], triangle.colors[0], triangle.ids[0], triCache, cornerVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals); var v1Left = AddTrianglePoint(triangle.pos[1], triangle.normal[1], triangle.uvs[1], triangle.tangents[1], triangle.colors[1], triangle.ids[1], triCache, cornerVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals); // Triangle (s0, v0, s1) triangles[idxLeft].Add(s0Left); triangles[idxLeft].Add(v0Left); triangles[idxLeft].Add(s1Left); // Triangle (s1, v0, v1) triangles[idxLeft].Add(s1Left); triangles[idxLeft].Add(v0Left); triangles[idxLeft].Add(v1Left); // right side ... 1 triangle var s0Right = AddIntersectionPoint(s0, triangle, triangle.ids[2], triangle.ids[0], cutVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals); var s1Right = AddIntersectionPoint(s1, triangle, triangle.ids[2], triangle.ids[1], cutVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals); var v2Right = AddTrianglePoint(triangle.pos[2], triangle.normal[2], triangle.uvs[2], triangle.tangents[2], triangle.colors[2], triangle.ids[2], triCache, cornerVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals); // Triangle (v2, s0, s1) triangles[idxRight].Add(v2Right); triangles[idxRight].Add(s0Right); triangles[idxRight].Add(s1Right); // buffer intersection vertices for triangulation if (triangulateHoles) { if (idxLeft == 0) { contour.AddTriangle(cutTri, s0Left, s1Left, s0, s1); } else { contour.AddTriangle(cutTri, s0Right, s1Right, s0, s1); } } } else if (side0 == side2) { var a = plane.IntersectSegment(triangle.pos[1], triangle.pos[0], out t0, ref s1); var b = plane.IntersectSegment(triangle.pos[1], triangle.pos[2], out t1, ref s0); ExploderUtils.Assert(a && b, "!!!!!!!!!!!!!"); // left side ... 2 triangles var s0Left = AddIntersectionPoint(s0, triangle, triangle.ids[1], triangle.ids[2], cutVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals); var s1Left = AddIntersectionPoint(s1, triangle, triangle.ids[1], triangle.ids[0], cutVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals); var v0Left = AddTrianglePoint(triangle.pos[0], triangle.normal[0], triangle.uvs[0], triangle.tangents[0], triangle.colors[0], triangle.ids[0], triCache, cornerVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals); var v2Left = AddTrianglePoint(triangle.pos[2], triangle.normal[2], triangle.uvs[2], triangle.tangents[2], triangle.colors[2], triangle.ids[2], triCache, cornerVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals); // Triangle (v2, s1, s0) triangles[idxLeft].Add(v2Left); triangles[idxLeft].Add(s1Left); triangles[idxLeft].Add(s0Left); // Triangle (v2, v0, s1) triangles[idxLeft].Add(v2Left); triangles[idxLeft].Add(v0Left); triangles[idxLeft].Add(s1Left); // right side ... 1 triangle var s0Right = AddIntersectionPoint(s0, triangle, triangle.ids[1], triangle.ids[2], cutVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals); var s1Right = AddIntersectionPoint(s1, triangle, triangle.ids[1], triangle.ids[0], cutVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals); var v1Right = AddTrianglePoint(triangle.pos[1], triangle.normal[1], triangle.uvs[1], triangle.tangents[1], triangle.colors[1], triangle.ids[1], triCache, cornerVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals); // Triangle (s0, s1, v1) triangles[idxRight].Add(s0Right); triangles[idxRight].Add(s1Right); triangles[idxRight].Add(v1Right); // buffer intersection vertices for triangulation if (triangulateHoles) { if (idxLeft == 0) { contour.AddTriangle(cutTri, s0Left, s1Left, s0, s1); } else { contour.AddTriangle(cutTri, s0Right, s1Right, s0, s1); } } } else { var a = plane.IntersectSegment(triangle.pos[0], triangle.pos[1], out t0, ref s0); var b = plane.IntersectSegment(triangle.pos[0], triangle.pos[2], out t1, ref s1); ExploderUtils.Assert(a && b, "!!!!!!!!!!!!!"); // right side ... 2 triangles var s0Right = AddIntersectionPoint(s0, triangle, triangle.ids[0], triangle.ids[1], cutVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals); var s1Right = AddIntersectionPoint(s1, triangle, triangle.ids[0], triangle.ids[2], cutVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals); var v1Right = AddTrianglePoint(triangle.pos[1], triangle.normal[1], triangle.uvs[1], triangle.tangents[1], triangle.colors[1], triangle.ids[1], triCache, cornerVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals); var v2Right = AddTrianglePoint(triangle.pos[2], triangle.normal[2], triangle.uvs[2], triangle.tangents[2], triangle.colors[2], triangle.ids[2], triCache, cornerVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals); // Triangle (v2, s1, v1) triangles[idxRight].Add(v2Right); triangles[idxRight].Add(s1Right); triangles[idxRight].Add(v1Right); // Triangle (s1, s0, v1) triangles[idxRight].Add(s1Right); triangles[idxRight].Add(s0Right); triangles[idxRight].Add(v1Right); // left side ... 1 triangle var s0Left = AddIntersectionPoint(s0, triangle, triangle.ids[0], triangle.ids[1], cutVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals); var s1Left = AddIntersectionPoint(s1, triangle, triangle.ids[0], triangle.ids[2], cutVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals); var v0Left = AddTrianglePoint(triangle.pos[0], triangle.normal[0], triangle.uvs[0], triangle.tangents[0], triangle.colors[0], triangle.ids[0], triCache, cornerVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals); // Triangle (s1, v0, s0) triangles[idxLeft].Add(s1Left); triangles[idxLeft].Add(v0Left); triangles[idxLeft].Add(s0Left); // buffer intersection vertices for triangulation if (triangulateHoles) { if (idxLeft == 0) { contour.AddTriangle(cutTri, s0Left, s1Left, s0, s1); } else { contour.AddTriangle(cutTri, s0Right, s1Right, s0, s1); } } } } #if PROFILING MeasureIt.End("CutCycleSecondPass"); #endif if (triangulateHoles) { #if PROFILING MeasureIt.Begin("FindContours"); #endif contour.FindContours(); if (contour.contour.Count == 0 || contour.contour[0].Count < 3) { if (allowOpenMesh) { triangulateHoles = false; } else { stopWatch.Stop(); return stopWatch.ElapsedMilliseconds; } } #if PROFILING MeasureIt.End("FindContours"); #endif } List<int>[] trianglesCut = null; if (triangulateHoles) { #if PROFILING MeasureIt.Begin("Triangulate"); #endif trianglesCut = new List<int>[2] {new List<int>(contour.MidPointsCount), new List<int>(contour.MidPointsCount)}; Triangulate(contour.contour, plane, vertices, normals, uvs, tangents, vertexColors, trianglesCut, true, useMeshTangents, useVertexColors, useNormals); #if PROFILING MeasureIt.End("Triangulate"); #endif } if (vertices[0].Count > 3 && vertices[1].Count > 3) { #if PROFILING MeasureIt.Begin("CutEndCopyBack"); #endif mesh0.mesh = new Mesh(); mesh1.mesh = new Mesh(); var verticesArray0 = vertices[0].ToArray(); var verticesArray1 = vertices[1].ToArray(); mesh0.mesh.vertices = verticesArray0; mesh0.mesh.uv = uvs[0].ToArray(); mesh1.mesh.vertices = verticesArray1; mesh1.mesh.uv = uvs[1].ToArray(); if (useNormals) { mesh0.mesh.normals = normals[0].ToArray(); mesh1.mesh.normals = normals[1].ToArray(); } if (useMeshTangents) { mesh0.mesh.tangents = tangents[0].ToArray(); mesh1.mesh.tangents = tangents[1].ToArray(); } if (useVertexColors) { mesh0.mesh.colors32 = vertexColors[0].ToArray(); mesh1.mesh.colors32 = vertexColors[1].ToArray(); } if (trianglesCut != null && trianglesCut[0].Count > 3) { triangles[0].AddRange(trianglesCut[0]); triangles[1].AddRange(trianglesCut[1]); } mesh0.mesh.triangles = triangles[0].ToArray(); mesh1.mesh.triangles = triangles[1].ToArray(); if (!triangulateHoles) { // don't triangulate holes means the mesh is a 2d plane // it is better to recalculate centroid to get precise center not just an approximation mesh0.centroid = Vector3.zero; mesh1.centroid = Vector3.zero; foreach (var p in vertices[0]) { mesh0.centroid += p; } mesh0.centroid /= vertices[0].Count; foreach (var p in vertices[1]) { mesh1.centroid += p; } mesh1.centroid /= vertices[1].Count; } #if PROFILING MeasureIt.End("CutEndCopyBack"); #endif meshes = new List<CutterMesh> { mesh0, mesh1 }; stopWatch.Stop(); return stopWatch.ElapsedMilliseconds; } stopWatch.Stop(); // UnityEngine.Debug.Log("Empty cut! " + vertices[0].Count + " " + vertices[1].Count); return stopWatch.ElapsedMilliseconds; }
bool ProcessCutter(out long cuttingTime) { ExploderUtils.Assert(state == State.ProcessCutter || state == State.DryRun, "Wrong state!"); var stopWatch = new Stopwatch(); stopWatch.Start(); bool cutting = true; bool timeBudgetStop = false; var cycleCounter = 0; while (cutting) { cycleCounter++; if (cycleCounter > settings.TargetFragments) { ExploderUtils.Log("Explode Infinite loop!"); break; } var fragmentsCount = meshSet.Count; newFragments.Clear(); meshToRemove.Clear(); cutting = false; foreach (var mesh in meshSet) { if (levelCount[mesh.level] > 0) { // TODO: for possible improvements change random value to something more sofisticated var randomPlaneNormal = Random.insideUnitSphere; if (!mesh.transform) { continue; } var plane = new Core.Math.Plane(randomPlaneNormal, mesh.transform.TransformPoint(mesh.centroid)); var triangulateHoles = true; var crossSectionVertexColour = Color.white; var crossSectionUV = new Vector4(0, 0, 1, 1); if (mesh.option) { triangulateHoles = !mesh.option.Plane2D; crossSectionVertexColour = mesh.option.CrossSectionVertexColor; crossSectionUV = mesh.option.CrossSectionUV; splitMeshIslands |= mesh.option.SplitMeshIslands; } if (settings.Use2DCollision) { triangulateHoles = false; } List<CutterMesh> meshes = null; cutter.Cut(mesh.mesh, mesh.transform, plane, triangulateHoles, settings.AllowOpenMeshCutting, ref meshes, crossSectionVertexColour, crossSectionUV); cutting = true; if (meshes != null) { foreach (var cutterMesh in meshes) { newFragments.Add(new CutMesh { mesh = cutterMesh.mesh, centroid = cutterMesh.centroid, material = mesh.material, vertices = mesh.vertices, transform = mesh.transform, distance = mesh.distance, level = mesh.level, fragments = mesh.fragments, original = mesh.original, skinnedOriginal = mesh.skinnedOriginal, parent = mesh.transform.parent, position = mesh.transform.position, rotation = mesh.transform.rotation, localScale = mesh.transform.localScale, option = mesh.option, }); } meshToRemove.Add(mesh); levelCount[mesh.level] -= 1; // stop this madness! if (fragmentsCount + newFragments.Count - meshToRemove.Count >= settings.TargetFragments) { cuttingTime = stopWatch.ElapsedMilliseconds; meshSet.ExceptWith(meshToRemove); meshSet.UnionWith(newFragments); return true; } // computation took more than settings.FrameBudget ... if (stopWatch.ElapsedMilliseconds > settings.FrameBudget) { timeBudgetStop = true; break; } } } } meshSet.ExceptWith(meshToRemove); meshSet.UnionWith(newFragments); if (timeBudgetStop) { break; } } cuttingTime = stopWatch.ElapsedMilliseconds; // explosion is finished if (!timeBudgetStop) { return true; } return false; }