Пример #1
0
 /// <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);
 }
Пример #2
0
        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;
            }
        }
Пример #3
0
        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;
        }
Пример #4
0
        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;
        }