Пример #1
0
    void Update()
    {
        if (Input.GetMouseButtonUp(0))
        {
            MeasureIt.Count("Clicks");
            MeasureIt.End("Time between Clicks (s)");
            MeasureIt.Begin("Time between Clicks (s)");
            Ray r = Camera.main.ScreenPointToRay(Input.mousePosition);
            transform.position = r.GetPoint(-Camera.main.transform.position.z);
        }

        transform.Rotate(new Vector3(20, 20, 20) * Time.deltaTime);
    }
Пример #2
0
        public void AddTriangle(int triangleID, int id0, int id1, Vector3 v0, Vector3 v1)
        {
#if PROFILING
            MeasureIt.Begin("AddTriangle");
#endif
            // we need to compute position hash to make sure we find all (duplicated) vertices with different edges
            int hash0, hash1;
            lsHash.Hash(v0, v1, out hash0, out hash1);

            // filter out points with similar positions
            if (hash0 == hash1)
            {
#if PROFILING
                MeasureIt.End("AddTriangle");
#endif
                return;
            }

            MidPoint midPoint;
            if (midPoints.TryGetValue(hash0, out midPoint))
            {
                if (midPoint.idNext == Int32.MaxValue && midPoint.idPrev != hash1)
                {
                    midPoint.idNext = hash1;
                }
                else if (midPoint.idPrev == Int32.MaxValue && midPoint.idNext != hash1)
                {
                    midPoint.idPrev = hash1;
                }

                midPoints[hash0] = midPoint;
            }
            else
            {
                midPoints.Add(hash0, new MidPoint {
                    id = hash0, vertexId = id0, idNext = hash1, idPrev = Int32.MaxValue                               /*, position = v0*/
                });
            }

            if (midPoints.TryGetValue(hash1, out midPoint))
            {
                if (midPoint.idNext == Int32.MaxValue && midPoint.idPrev != hash0)
                {
                    midPoint.idNext = hash0;
                }
                else if (midPoint.idPrev == Int32.MaxValue && midPoint.idNext != hash0)
                {
                    midPoint.idPrev = hash0;
                }

                midPoints[hash1] = midPoint;
            }
            else
            {
                midPoints.Add(hash1, new MidPoint {
                    id = hash1, vertexId = id1, idPrev = hash0, idNext = Int32.MaxValue                                /*, position = v1*/
                });
            }

            MidPointsCount = midPoints.Count;

#if PROFILING
            MeasureIt.End("AddTriangle");
#endif
        }
Пример #3
0
        float Cut(ExploderMesh mesh, ExploderTransform meshTransform, Plane plane, bool triangulateHoles, bool allowOpenMesh, ref List <ExploderMesh> 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);

            ExploderMesh mesh0, mesh1;

#if PROFILING
            MeasureIt.End("CutAllocations");
            MeasureIt.Begin("CutCycleFirstPass");
#endif

            // 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;
            }

//            UnityEngine.Debug.LogFormat("cut: {0} -- {1}, normal: {2}, tris: {3}", vertices[0].Count, vertices[1].Count, plane.Normal, cutTris.Count);

#if PROFILING
            MeasureIt.End("CutCycleFirstPass");
            MeasureIt.Begin("CutCycleSecondPass");
#endif

            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)
                {
//                    triangulateHoles = false;

                    if (allowOpenMesh)
                    {
                        triangulateHoles = false;
                    }
                    else
                    {
                        stopWatch.Stop();
                        return(stopWatch.ElapsedMilliseconds);
                    }
                }

#if PROFILING
                MeasureIt.End("FindContours");
#endif
            }

            List <int>[] trianglesCut = null;
            var          centroid0    = Vector3.zero;
            var          centroid1    = Vector3.zero;
            var          min0         = Vector3.zero;
            var          max0         = Vector3.zero;
            var          min1         = Vector3.zero;
            var          max1         = Vector3.zero;

            ExploderMesh.CalculateCentroid(vertices[0], ref centroid0, ref min0, ref max0);
            ExploderMesh.CalculateCentroid(vertices[1], ref centroid1, ref min1, ref max1);

            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 = new ExploderMesh();
                mesh1 = new ExploderMesh();

                var verticesArray0 = vertices[0].ToArray();
                var verticesArray1 = vertices[1].ToArray();

                mesh0.vertices = verticesArray0;
                mesh0.uv       = uvs[0].ToArray();

                mesh1.vertices = verticesArray1;
                mesh1.uv       = uvs[1].ToArray();

                if (useNormals)
                {
                    mesh0.normals = normals[0].ToArray();
                    mesh1.normals = normals[1].ToArray();
                }

                if (useMeshTangents)
                {
                    mesh0.tangents = tangents[0].ToArray();
                    mesh1.tangents = tangents[1].ToArray();
                }

                if (useVertexColors)
                {
                    mesh0.colors32 = vertexColors[0].ToArray();
                    mesh1.colors32 = vertexColors[1].ToArray();
                }

                if (trianglesCut != null && trianglesCut[0].Count > 3)
                {
                    triangles[0].AddRange(trianglesCut[0]);
                    triangles[1].AddRange(trianglesCut[1]);
                }

                mesh0.triangles = triangles[0].ToArray();
                mesh1.triangles = triangles[1].ToArray();

                mesh0.centroid = centroid0;
                mesh0.min      = min0;
                mesh0.max      = max0;

                mesh1.centroid = centroid1;
                mesh1.min      = min1;
                mesh1.max      = max1;

#if PROFILING
                MeasureIt.End("CutEndCopyBack");
#endif

                meshes = new List <ExploderMesh> {
                    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
        private float Cut(Mesh mesh, Transform meshTransform, Utils.Plane plane, bool triangulateHoles, bool fixPivot, bool getContourList, bool dontCut,
                          Vector4 crossSection, out Mesh mesh0, out Mesh mesh1, out Vector3 centroid0, out Vector3 centroid1, out ContourData intersectionData)
        {
            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 meshVertices  = mesh.vertices;
            var meshNormals   = mesh.normals;
            var meshUV        = mesh.uv;

            this.crossSectionUV = crossSection;

            // preallocate buffers
            AllocateBuffers(trianglesNum, verticesNum);

#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 (var 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;

                // all points on one side
                if (side0 == side1 && side1 == side2)
                {
                    var idx = side0 ? 0 : 1;

                    if (triCache[meshTriangles[i]] == 0)
                    {
                        triangles[idx].Add(triCounter[idx]);
                        vertices[idx].Add(meshVertices[meshTriangles[i]]);
                        normals[idx].Add(meshNormals[meshTriangles[i]]);
                        uvs[idx].Add(meshUV[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]]);
                        normals[idx].Add(meshNormals[meshTriangles[i + 1]]);
                        uvs[idx].Add(meshUV[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]]);
                        normals[idx].Add(meshNormals[meshTriangles[i + 2]]);
                        uvs[idx].Add(meshUV[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            = null;
            mesh1            = null;
            centroid0        = centroid[0];
            centroid1        = centroid[1];
            intersectionData = 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 = new[] { meshNormals[meshTriangles[cutTri + 0]], meshNormals[meshTriangles[cutTri + 1]], meshNormals[meshTriangles[cutTri + 2]] },
                    uvs    = new[] { meshUV[meshTriangles[cutTri + 0]], meshUV[meshTriangles[cutTri + 1]], meshUV[meshTriangles[cutTri + 2]] }
                };

                // 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, s1;

                var idxLeft  = side0 ? 0 : 1;
                var idxRight = 1 - idxLeft;

                if (side0 == side1)
                {
                    var a = plane.IntersectSegment(triangle.pos[2], triangle.pos[0], out t0, out s0);
                    var b = plane.IntersectSegment(triangle.pos[2], triangle.pos[1], out t1, out s1);

                    MeshUtils.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]);
                    var s1Left = AddIntersectionPoint(s1, triangle, triangle.ids[2], triangle.ids[1], cutVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft]);
                    var v0Left = AddTrianglePoint(triangle.pos[0], triangle.normal[0], triangle.uvs[0], triangle.ids[0], triCache, cornerVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft]);
                    var v1Left = AddTrianglePoint(triangle.pos[1], triangle.normal[1], triangle.uvs[1], triangle.ids[1], triCache, cornerVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft]);

                    // 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]);
                    var s1Right = AddIntersectionPoint(s1, triangle, triangle.ids[2], triangle.ids[1], cutVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight]);
                    var v2Right = AddTrianglePoint(triangle.pos[2], triangle.normal[2], triangle.uvs[2], triangle.ids[2], triCache, cornerVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight]);

                    // 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, out s1);
                    var b = plane.IntersectSegment(triangle.pos[1], triangle.pos[2], out t1, out s0);

                    MeshUtils.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]);
                    var s1Left = AddIntersectionPoint(s1, triangle, triangle.ids[1], triangle.ids[0], cutVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft]);
                    var v0Left = AddTrianglePoint(triangle.pos[0], triangle.normal[0], triangle.uvs[0], triangle.ids[0], triCache, cornerVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft]);
                    var v2Left = AddTrianglePoint(triangle.pos[2], triangle.normal[2], triangle.uvs[2], triangle.ids[2], triCache, cornerVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft]);

                    // 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]);
                    var s1Right = AddIntersectionPoint(s1, triangle, triangle.ids[1], triangle.ids[0], cutVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight]);
                    var v1Right = AddTrianglePoint(triangle.pos[1], triangle.normal[1], triangle.uvs[1], triangle.ids[1], triCache, cornerVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight]);

                    // 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, out s0);
                    var b = plane.IntersectSegment(triangle.pos[0], triangle.pos[2], out t1, out s1);

                    MeshUtils.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]);
                    var s1Right = AddIntersectionPoint(s1, triangle, triangle.ids[0], triangle.ids[2], cutVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight]);
                    var v1Right = AddTrianglePoint(triangle.pos[1], triangle.normal[1], triangle.uvs[1], triangle.ids[1], triCache, cornerVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight]);
                    var v2Right = AddTrianglePoint(triangle.pos[2], triangle.normal[2], triangle.uvs[2], triangle.ids[2], triCache, cornerVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight]);

                    // 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]);
                    var s1Left = AddIntersectionPoint(s1, triangle, triangle.ids[0], triangle.ids[2], cutVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft]);
                    var v0Left = AddTrianglePoint(triangle.pos[0], triangle.normal[0], triangle.uvs[0], triangle.ids[0], triCache, cornerVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft]);

                    // 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 || getContourList)
            {
#if PROFILING
                MeasureIt.Begin("FindContours");
#endif

                contour.FindContours();

#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, trianglesCut, true);

#if PROFILING
                MeasureIt.End("Triangulate");
#endif
            }

            intersectionData = null;

            if (getContourList)
            {
#if PROFILING
                MeasureIt.Begin("GetContourList");
#endif
                List <Vector3[]> contoursList = null;

                GetContourList(contour.contour, vertices[0], out contoursList);

                intersectionData = new ContourData(contoursList, meshTransform);

#if PROFILING
                MeasureIt.End("GetContourList");
#endif
            }

            centroid0 = centroid[0];
            centroid1 = centroid[1];

            if (dontCut)
            {
                MeshUtils.Assert(intersectionData != null, "F**k");
                MeshUtils.Assert(getContourList != false, "Fuck2");
                mesh0 = null;
                mesh1 = null;
                return(stopWatch.ElapsedMilliseconds);
            }

            if (vertices[0].Count > 0 && vertices[1].Count > 0)
            {
#if PROFILING
                MeasureIt.Begin("CutEndCopyBack");
#endif

                mesh0 = new Mesh();
                mesh1 = new Mesh();

                var verticesArray0 = vertices[0].ToArray();
                var verticesArray1 = vertices[1].ToArray();

#if PROFILING
                MeasureIt.Begin("FixPivot");
#endif

                if (fixPivot)
                {
                    MeshUtils.CenterPivot(verticesArray0, centroid[0]);
                    MeshUtils.CenterPivot(verticesArray1, centroid[1]);
                }

#if PROFILING
                MeasureIt.End("FixPivot");
#endif

                mesh0.vertices = verticesArray0;
                mesh0.normals  = normals[0].ToArray();
                mesh0.uv       = uvs[0].ToArray();

                mesh1.vertices = verticesArray1;
                mesh1.normals  = normals[1].ToArray();
                mesh1.uv       = uvs[1].ToArray();

                if (triangulateHoles && trianglesCut[0].Count > 0)
                {
                    mesh0.subMeshCount = 2;
                    mesh0.SetTriangles(triangles[0].ToArray(), 0);
                    mesh0.SetTriangles(trianglesCut[0].ToArray(), 1);

                    mesh1.subMeshCount = 2;
                    mesh1.SetTriangles(triangles[1].ToArray(), 0);
                    mesh1.SetTriangles(trianglesCut[1].ToArray(), 1);
                }
                else
                {
                    mesh0.triangles = triangles[0].ToArray();
                    mesh1.triangles = triangles[1].ToArray();
                }

#if PROFILING
                MeasureIt.End("CutEndCopyBack");
#endif

                stopWatch.Stop();
                return(stopWatch.ElapsedMilliseconds);
            }

            mesh0 = null;
            mesh1 = null;
            stopWatch.Stop();

//            UnityEngine.Debug.Log("Empty cut! " + vertices[0].Count + " " + vertices[1].Count);

            return(stopWatch.ElapsedMilliseconds);
        }
Пример #5
0
        /// <summary>
        /// cut mesh by plane
        /// </summary>
        /// <param name="spriteMesh">mesh to cut</param>
        /// <param name="meshTransform">transformation of the mesh</param>
        /// <param name="line2D">cutting plane</param>
        /// <returns>processing time</returns>
        public float Cut(SpriteMesh spriteMesh, Transform meshTransform, Math.Line2D line2D, ref List <CutterMesh> meshes)
        {
            var stopWatch = new Stopwatch();

            stopWatch.Start();

#if PROFILING
            MeasureIt.Begin("CutAllocations");
#endif

            // cache mesh data
            var trianglesNum  = spriteMesh.triangles.Length;
            var verticesNum   = spriteMesh.vertices.Length;
            var meshTriangles = spriteMesh.triangles;
            var meshVertices  = spriteMesh.vertices;

            // preallocate buffers
            AllocateBuffers(trianglesNum, verticesNum);

            CutterMesh mesh0, mesh1;

#if PROFILING
            MeasureIt.End("CutAllocations");
            MeasureIt.Begin("CutCycleFirstPass");
#endif

            // inverse transform cutting plane
            // line2D.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 = line2D.GetSideFix(ref v0);
                var side1 = line2D.GetSideFix(ref v1);
                var side2 = line2D.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)
                    {
                        Exploder2DUtils.Log("TriCacheError " + meshTriangles[i] + " " + triCache.Length + " " + meshVertices.Length);
                    }

                    if (triCache[meshTriangles[i]] == 0)
                    {
                        triangles[idx].Add(triCounter[idx]);
                        vertices[idx].Add(meshVertices[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]]);

                        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]]);

                        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.centroidLocal = centroid[0];
            mesh1.centroidLocal = 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]] },
                };

                // check points with a plane
                var side0 = line2D.GetSide(triangle.pos[0]);
                var side1 = line2D.GetSide(triangle.pos[1]);
                var side2 = line2D.GetSide(triangle.pos[2]);

                float   t0, t1;
                Vector2 s0 = Vector2.zero, s1 = Vector2.zero;

                var idxLeft  = side0 ? 0 : 1;
                var idxRight = 1 - idxLeft;

                if (side0 == side1)
                {
                    var a = line2D.IntersectSegment(triangle.pos[2], triangle.pos[0], out t0, ref s0);
                    var b = line2D.IntersectSegment(triangle.pos[2], triangle.pos[1], out t1, ref s1);

                    Exploder2DUtils.Assert(a && b, "!!!!!!!!!!!!!!!");

                    // left side ... 2 triangles
                    var s0Left = AddIntersectionPoint(s0, triangle.ids[2], triangle.ids[0], cutVertCache[idxLeft], vertices[idxLeft]);
                    var s1Left = AddIntersectionPoint(s1, triangle.ids[2], triangle.ids[1], cutVertCache[idxLeft], vertices[idxLeft]);
                    var v0Left = AddTrianglePoint(triangle.pos[0], triangle.ids[0], triCache, cornerVertCache[idxLeft], vertices[idxLeft]);
                    var v1Left = AddTrianglePoint(triangle.pos[1], triangle.ids[1], triCache, cornerVertCache[idxLeft], vertices[idxLeft]);

                    // 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.ids[2], triangle.ids[0], cutVertCache[idxRight], vertices[idxRight]);
                    var s1Right = AddIntersectionPoint(s1, triangle.ids[2], triangle.ids[1], cutVertCache[idxRight], vertices[idxRight]);
                    var v2Right = AddTrianglePoint(triangle.pos[2], triangle.ids[2], triCache, cornerVertCache[idxRight], vertices[idxRight]);

                    // Triangle (v2, s0, s1)
                    triangles[idxRight].Add(v2Right);
                    triangles[idxRight].Add(s0Right);
                    triangles[idxRight].Add(s1Right);
                }
                else if (side0 == side2)
                {
                    var a = line2D.IntersectSegment(triangle.pos[1], triangle.pos[0], out t0, ref s1);
                    var b = line2D.IntersectSegment(triangle.pos[1], triangle.pos[2], out t1, ref s0);

                    Exploder2DUtils.Assert(a && b, "!!!!!!!!!!!!!");

                    // left side ... 2 triangles
                    var s0Left = AddIntersectionPoint(s0, triangle.ids[1], triangle.ids[2], cutVertCache[idxLeft], vertices[idxLeft]);
                    var s1Left = AddIntersectionPoint(s1, triangle.ids[1], triangle.ids[0], cutVertCache[idxLeft], vertices[idxLeft]);
                    var v0Left = AddTrianglePoint(triangle.pos[0], triangle.ids[0], triCache, cornerVertCache[idxLeft], vertices[idxLeft]);
                    var v2Left = AddTrianglePoint(triangle.pos[2], triangle.ids[2], triCache, cornerVertCache[idxLeft], vertices[idxLeft]);

                    // 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.ids[1], triangle.ids[2], cutVertCache[idxRight], vertices[idxRight]);
                    var s1Right = AddIntersectionPoint(s1, triangle.ids[1], triangle.ids[0], cutVertCache[idxRight], vertices[idxRight]);
                    var v1Right = AddTrianglePoint(triangle.pos[1], triangle.ids[1], triCache, cornerVertCache[idxRight], vertices[idxRight]);

                    // Triangle (s0, s1, v1)
                    triangles[idxRight].Add(s0Right);
                    triangles[idxRight].Add(s1Right);
                    triangles[idxRight].Add(v1Right);
                }
                else
                {
                    var a = line2D.IntersectSegment(triangle.pos[0], triangle.pos[1], out t0, ref s0);
                    var b = line2D.IntersectSegment(triangle.pos[0], triangle.pos[2], out t1, ref s1);

                    Exploder2DUtils.Assert(a && b, "!!!!!!!!!!!!!");

                    // right side ... 2 triangles
                    var s0Right = AddIntersectionPoint(s0, triangle.ids[0], triangle.ids[1], cutVertCache[idxRight], vertices[idxRight]);
                    var s1Right = AddIntersectionPoint(s1, triangle.ids[0], triangle.ids[2], cutVertCache[idxRight], vertices[idxRight]);
                    var v1Right = AddTrianglePoint(triangle.pos[1], triangle.ids[1], triCache, cornerVertCache[idxRight], vertices[idxRight]);
                    var v2Right = AddTrianglePoint(triangle.pos[2], triangle.ids[2], triCache, cornerVertCache[idxRight], vertices[idxRight]);

                    // 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.ids[0], triangle.ids[1], cutVertCache[idxLeft], vertices[idxLeft]);
                    var s1Left = AddIntersectionPoint(s1, triangle.ids[0], triangle.ids[2], cutVertCache[idxLeft], vertices[idxLeft]);
                    var v0Left = AddTrianglePoint(triangle.pos[0], triangle.ids[0], triCache, cornerVertCache[idxLeft], vertices[idxLeft]);

                    // Triangle (s1, v0, s0)
                    triangles[idxLeft].Add(s1Left);
                    triangles[idxLeft].Add(v0Left);
                    triangles[idxLeft].Add(s0Left);
                }
            }

#if PROFILING
            MeasureIt.End("CutCycleSecondPass");
#endif

            List <int>[] trianglesCut = null;

            if (vertices[0].Count > 3 && vertices[1].Count > 3)
            {
#if PROFILING
                MeasureIt.Begin("CutEndCopyBack");
#endif

                mesh0.mesh = new SpriteMesh();
                mesh1.mesh = new SpriteMesh();

                var verticesArray0 = vertices[0].ToArray();
                var verticesArray1 = vertices[1].ToArray();

                mesh0.mesh.vertices = verticesArray0;
                mesh1.mesh.vertices = verticesArray1;

                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();

                mesh0.centroidLocal = Vector2.zero;
                mesh1.centroidLocal = Vector2.zero;

                foreach (var p in vertices[0])
                {
                    mesh0.centroidLocal += p;
                }
                mesh0.centroidLocal /= vertices[0].Count;

                foreach (var p in vertices[1])
                {
                    mesh1.centroidLocal += p;
                }
                mesh1.centroidLocal /= 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);
        }