public static void SortMesh(Mesh targetMesh, Triangle3D[] triangleBucket, int triangleBucketCount, Transform objectTransform, List <Triangle3D> capTriBucket, List <Triangle3D.Vertex> capVertBucket, bool flip)
    {
        Dictionary <int, int> vertCache = new Dictionary <int, int>(triangleBucketCount * 3);

        Triangle3D.Vertex vert = null;

        int vertexBucketCount = 0;

        Vector3[] vertexBucket = new Vector3[triangleBucketCount * 3];
        for (int i = 0; i < triangleBucketCount; i++)
        {
            Triangle3D triangle = triangleBucket[i];
            for (int j = 0; j < triangle.vertices.Length; j++)
            {
                vert = triangle.vertices[j];
                int code = vert.GetHashCode();
                if (!vertCache.ContainsKey(code))
                {
                    vertCache[code]                 = vertexBucketCount;
                    triangle.vertices[j]            = vert;
                    triangle.indices[j]             = vertexBucketCount;
                    vertexBucket[vertexBucketCount] = objectTransform.InverseTransformPoint(vert.pos);
                    vertexBucketCount++;
                }
                else
                {
                    triangle.indices[j] = vertCache[code];
                }
            }
        }

        int triWithCapCount  = triangleBucketCount + capTriBucket.Count;
        int vertWithCapCount = vertexBucketCount + capVertBucket.Count;

        Array.Resize <Triangle3D>(ref triangleBucket, triangleBucketCount + capTriBucket.Count);
        Array.Resize <Vector3>(ref vertexBucket, vertexBucketCount + capVertBucket.Count);

        int triOff = 0;

        for (int i = triangleBucketCount; i < triWithCapCount; i++)
        {
            triangleBucket[i] = new Triangle3D(capTriBucket[triOff++], vertexBucketCount, flip);
        }
        int vertOff = 0;

        for (int i = vertexBucketCount; i < vertWithCapCount; i++)
        {
            vertexBucket[i] = capVertBucket[vertOff++].pos;
        }
        CreateNewMesh(targetMesh, triangleBucket, vertexBucket);
    }
    public static SplitMesh GrabMeshOutline(Mesh mesh, Plane cuttingPlane, Transform transform, Transform rotation)
    {
        debugPolyLoop = new List<Vector3>();
        debugEdgePoints = new List<Vector3>();
        debugEdges = new List<Vector3[]>();
        debugLoopEdgePoints = new List<Vector3[]>();

        int vertCount = mesh.vertexCount;
        Vector3[] verts = mesh.vertices;
        Triangle3D.Vertex[] allVerts = new Triangle3D.Vertex[vertCount];
        for (int i = 0; i < vertCount; i++)
        {
            allVerts[i] = new Triangle3D.Vertex(transform.TransformPoint(verts[i]));
        }

        List<Triangle3D.Vertex> allVertList = new List<Triangle3D.Vertex>();
        Vector2[] originalUVs = mesh.uv;
        Vector3[] originalNormals = mesh.normals;
        Vector4[] originalTangents = mesh.tangents;

        int triCount = mesh.triangles.Length / 3;
        Triangle3D[] originalTriangles = new Triangle3D[triCount];

        int offset = 0;
        for (int j = 0; j < mesh.subMeshCount; j++)
        {
            uint triOffset = 0;
            int[] subMeshIndices = mesh.GetTriangles(j);
            int subMeshTriCount = subMeshIndices.Length / 3;

            for (int i = 0; i < subMeshTriCount; i++)
            {
                int idx0 = subMeshIndices[triOffset + 0];
                int idx1 = subMeshIndices[triOffset + 1];
                int idx2 = subMeshIndices[triOffset + 2];

                if (originalTriangles.Length <= offset)
                {
                    Debug.Log("Error");
                }

                originalTriangles[offset++] = new Triangle3D(allVertList, new Triangle3D.Vertex[] { allVerts[idx0], allVerts[idx1], allVerts[idx2] }, new Vector3[] { originalNormals[idx0], originalNormals[idx1], originalNormals[idx2] }, new Vector2[] { originalUVs[idx0], originalUVs[idx1], originalUVs[idx2] }, new Vector4[] { originalTangents[idx0], originalTangents[idx1], originalTangents[idx2] }, new int[] { subMeshIndices[triOffset + 0], subMeshIndices[triOffset + 1], subMeshIndices[triOffset + 2] }, j);

                triOffset += 3;
            }
        }

        if (originalTriangles.Length > 0)
        {
            int processedTriCount = 0;
            Triangle3D[] processedTris = new Triangle3D[originalTriangles.Length * 3];

            ClassificationUtil.Classification prevSide = ClassificationUtil.Classification.UNDEFINED;
            foreach (Triangle3D originalTriangle in originalTriangles)
            {
                ClassificationUtil.Classification side;
                Triangle3D[] splitTriangles = TriangleUtil.SplitTriangleWithPlane(originalTriangle, cuttingPlane, float.Epsilon, out side);
                if (prevSide != ClassificationUtil.Classification.UNDEFINED && prevSide != side)
                {
                }
                prevSide = side;
                if (splitTriangles != null)
                {
                    // Triangle was cut
                    foreach (Triangle3D splitTriangle in splitTriangles)
                    {
                        processedTris[processedTriCount] = splitTriangle;
                        processedTriCount++;

                    }
                }

                else
                {
                    // Triangle was not cut
                    processedTris[processedTriCount] = originalTriangle;
                    processedTriCount++;

                }
            }

            int triangleBucketACount = 0;
            int triangleBucketBCount = 0;
            Triangle3D[] triangleBucketA = new Triangle3D[processedTriCount];
            Triangle3D[] triangleBucketB = new Triangle3D[processedTriCount];
            for (int i = 0; i < processedTriCount; i++)
            {
                ClassificationUtil.Classification[] classes;
                ClassificationUtil.Classification triClass = ClassificationUtil.ClassifyPoints(processedTris[i].pos, cuttingPlane, out classes, float.Epsilon);

                if (triClass == ClassificationUtil.Classification.FRONT)
                {
                    triangleBucketA[triangleBucketACount++] = processedTris[i];
                }

                else if (triClass == ClassificationUtil.Classification.BACK)
                {
                    triangleBucketB[triangleBucketBCount++] = processedTris[i];
                }
            }

            if (triangleBucketACount == 0 || triangleBucketBCount == 0)
            {
                return null;
            }

            List<Triangle3D> totalCapTriBucket = new List<Triangle3D>();
            List<Triangle3D.Vertex> totalCapVertBucket = new List<Triangle3D.Vertex>();
            List<List<Triangle3D.Vertex>> capVertGroups = new List<List<Triangle3D.Vertex>>();
            while (debugEdges.Count > 2)
            {
                List<Triangle3D> capTriBucket = new List<Triangle3D>();
                List<Triangle3D.Vertex> capVertBucket = new List<Triangle3D.Vertex>();
                Triangle3D.Vertex[] sortedVerts = GetPolyLoop(ref debugEdges);
                if (sortedVerts != null)
                {
                    CapMesh(out capTriBucket, out capVertBucket, sortedVerts, transform, rotation, totalCapTriBucket.Count);
                }
        #if false
                if(capVertBucket.Count > 2)
                {
                    for(int i = 0; i < capVertBucket.Count - 1; i++)
                    {
                        Debug.DrawLine(transform.TransformPoint(capVertBucket[i].pos), transform.TransformPoint(capVertBucket[i + 1].pos));
                    }
                    Debug.DrawLine(transform.TransformPoint(capVertBucket[capVertBucket.Count - 1].pos), transform.TransformPoint(capVertBucket[0].pos));
                }
        #endif
                totalCapTriBucket.AddRange(capTriBucket);
                totalCapVertBucket.AddRange(capVertBucket);
                capVertGroups.Add(capVertBucket);
            }

            Vector3[] vertexBucket = new Vector3[totalCapVertBucket.Count];
            for (int i = 0; i < totalCapVertBucket.Count; i++)
            {
                vertexBucket[i] = transform.TransformPoint(totalCapVertBucket[i].pos);
            }

            return new SplitMesh(new List<Vector3>(vertexBucket), totalCapTriBucket, capVertGroups);
        }

        else
        {
            Debug.LogError("Source geometry empty");
            return null;
        }
    }
    public static bool CutTriangleMeshOneSide(Mesh outputMeshes, Mesh sourceMesh, Plane cuttingPlane, Transform transform, Transform rotation, bool frontSide, bool cap)
    {
        float epsilon = 0.00001f;

        hashCheck = new Dictionary<Vector3, int>();
        debugPolyLoop = new List<Vector3>();
        debugEdgePoints = new List<Vector3>();
        debugEdges = new List<Vector3[]>();
        debugLoopEdgePoints = new List<Vector3[]>();

        int vertCount = sourceMesh.vertexCount;
        Vector3[] verts = sourceMesh.vertices;
        Triangle3D.Vertex[] allVerts = new Triangle3D.Vertex[vertCount];
        for (int i = 0; i < vertCount; i++)
        {
            allVerts[i] = new Triangle3D.Vertex(transform.TransformPoint(verts[i]));
        }

        List<Triangle3D.Vertex> allVertList = new List<Triangle3D.Vertex>();
        //int[] originalIndices = sourceMesh.triangles;
        Vector2[] originalUVs = sourceMesh.uv;
        Vector3[] originalNormals = sourceMesh.normals;
        Vector4[] originalTangents = sourceMesh.tangents;

        int triCount = sourceMesh.triangles.Length / 3;
        Triangle3D[] originalTriangles = new Triangle3D[triCount];

        int offset = 0;
        for (int j = 0; j < sourceMesh.subMeshCount; j++)
        {
            uint triOffset = 0;
            int[] subMeshIndices = sourceMesh.GetTriangles(j);
            int subMeshTriCount = subMeshIndices.Length / 3;

            for (int i = 0; i < subMeshTriCount; i++)
            {
                int idx0 = subMeshIndices[triOffset + 0];
                int idx1 = subMeshIndices[triOffset + 1];
                int idx2 = subMeshIndices[triOffset + 2];
                originalTriangles[offset++] = new Triangle3D(allVertList, new Triangle3D.Vertex[] { allVerts[idx0], allVerts[idx1], allVerts[idx2] }, new Vector3[] { originalNormals[idx0], originalNormals[idx1], originalNormals[idx2] }, new Vector2[] { originalUVs[idx0], originalUVs[idx1], originalUVs[idx2] }, new Vector4[] { originalTangents[idx0], originalTangents[idx1], originalTangents[idx2] }, new int[] { subMeshIndices[triOffset + 0], subMeshIndices[triOffset + 1], subMeshIndices[triOffset + 2] }, j);
                triOffset += 3;
            }
        }

        if (originalTriangles.Length > 0)
        {
            int processedTriCount = 0;
            Triangle3D[] processedTris = new Triangle3D[originalTriangles.Length * 3];

            ClassificationUtil.Classification prevSide = ClassificationUtil.Classification.UNDEFINED;
            foreach (Triangle3D originalTriangle in originalTriangles)
            {
                ClassificationUtil.Classification side;
                Triangle3D[] splitTriangles = TriangleUtil.SplitTriangleWithPlane(originalTriangle, cuttingPlane, epsilon, out side, cap);
                if (prevSide != ClassificationUtil.Classification.UNDEFINED && prevSide != side)
                {
                }
                prevSide = side;
                if (splitTriangles != null)
                {
                    foreach (Triangle3D splitTriangle in splitTriangles)
                    {
                        processedTris[processedTriCount] = splitTriangle;
                        processedTriCount++;
                    }
                }

                else
                {
                    processedTris[processedTriCount] = originalTriangle;
                    processedTriCount++;
                }
            }

            //if (!cut)
            //{
            //    CloneMesh(sourceMesh, outputMeshes);
            //    return false;
            //}

            int triangleBucketCount = 0;
            Triangle3D[] triangleBucket = new Triangle3D[processedTriCount];
            for (int i = 0; i < processedTriCount; i++)
            {
                ClassificationUtil.Classification[] classes;
                ClassificationUtil.Classification triClass = ClassificationUtil.ClassifyPoints(processedTris[i].pos, cuttingPlane, out classes, epsilon);

                if (triClass == ClassificationUtil.Classification.FRONT && frontSide)
                {
                    triangleBucket[triangleBucketCount++] = processedTris[i];
                }

                else if (triClass == ClassificationUtil.Classification.BACK && !frontSide)
                {
                    triangleBucket[triangleBucketCount++] = processedTris[i];
                }
            }

            if (triangleBucketCount == 0)
            {
                outputMeshes.Clear();
                return false;
            }

            List<Triangle3D> totalCapTriBucket = new List<Triangle3D>();
            List<Triangle3D.Vertex> totalCapVertBucket = new List<Triangle3D.Vertex>();

            while (cap && debugEdges.Count > 2)
            {
                List<Triangle3D> capTriBucket = new List<Triangle3D>();
                List<Triangle3D.Vertex> capVertBucket = new List<Triangle3D.Vertex>();
                Triangle3D.Vertex[] sortedVerts = GetPolyLoop(ref debugEdges);

                if (sortedVerts != null)
                {
                    CapMesh(out capTriBucket, out capVertBucket, sortedVerts, transform, rotation, totalCapTriBucket.Count);
                }

                totalCapTriBucket.AddRange(capTriBucket);
                totalCapVertBucket.AddRange(capVertBucket);
            }

            if (triangleBucketCount > 0)
            {
                SortMesh(outputMeshes, triangleBucket, triangleBucketCount, transform, totalCapTriBucket, totalCapVertBucket, !frontSide);
            }
            return true;
        }

        else
        {
            return false;
        }
    }
    public static bool CutTriangleMesh(Mesh[] outputMeshes, Mesh sourceMesh, Plane cuttingPlane, Transform transform, Transform rotation, bool cap)
    {
        float epsilon = 0.00001f;

        debugPolyLoop       = new List <Vector3>();
        debugEdgePoints     = new List <Vector3>();
        debugEdges          = new List <Vector3[]>();
        debugLoopEdgePoints = new List <Vector3[]>();

        int vertCount = sourceMesh.vertexCount;

        Vector3[]           verts    = sourceMesh.vertices;
        Triangle3D.Vertex[] allVerts = new Triangle3D.Vertex[vertCount];
        for (int i = 0; i < vertCount; i++)
        {
            allVerts[i] = new Triangle3D.Vertex(transform.TransformPoint(verts[i]));
        }

        List <Triangle3D.Vertex> allVertList = new List <Triangle3D.Vertex>();

        Vector2[] originalUVs      = sourceMesh.uv;
        Vector3[] originalNormals  = sourceMesh.normals;
        Vector4[] originalTangents = sourceMesh.tangents;

        int triCount = sourceMesh.triangles.Length / 3;

        Triangle3D[] originalTriangles = new Triangle3D[triCount];

        int offset = 0;

        for (int j = 0; j < sourceMesh.subMeshCount; j++)
        {
            uint  triOffset       = 0;
            int[] subMeshIndices  = sourceMesh.GetTriangles(j);
            int   subMeshTriCount = subMeshIndices.Length / 3;

            for (int i = 0; i < subMeshTriCount; i++)
            {
                int idx0 = subMeshIndices[triOffset + 0];
                int idx1 = subMeshIndices[triOffset + 1];
                int idx2 = subMeshIndices[triOffset + 2];


                originalTriangles[offset++] = new Triangle3D(allVertList, new Triangle3D.Vertex[] { allVerts[idx0], allVerts[idx1], allVerts[idx2] }, new Vector3[] { originalNormals[idx0], originalNormals[idx1], originalNormals[idx2] }, new Vector2[] { originalUVs[idx0], originalUVs[idx1], originalUVs[idx2] }, new Vector4[] { originalTangents[idx0], originalTangents[idx1], originalTangents[idx2] }, new int[] { subMeshIndices[triOffset + 0], subMeshIndices[triOffset + 1], subMeshIndices[triOffset + 2] }, j);

                triOffset += 3;
            }
        }

        if (originalTriangles.Length > 0)
        {
            int          processedTriCount = 0;
            Triangle3D[] processedTris     = new Triangle3D[originalTriangles.Length * 3];

            ClassificationUtil.Classification prevSide = ClassificationUtil.Classification.UNDEFINED;
            foreach (Triangle3D originalTriangle in originalTriangles)
            {
                ClassificationUtil.Classification side;
                Triangle3D[] splitTriangles = TriangleUtil.SplitTriangleWithPlane(originalTriangle, cuttingPlane, epsilon, out side, cap);
                if (prevSide != ClassificationUtil.Classification.UNDEFINED && prevSide != side)
                {
                }
                prevSide = side;
                if (splitTriangles != null)
                {
                    // Triangle was cut
                    foreach (Triangle3D splitTriangle in splitTriangles)
                    {
                        processedTris[processedTriCount] = splitTriangle;
                        processedTriCount++;
                    }
                }

                else
                {
                    // Triangle was not cut
                    processedTris[processedTriCount] = originalTriangle;
                    processedTriCount++;
                }
            }

            int          triangleBucketACount = 0;
            int          triangleBucketBCount = 0;
            Triangle3D[] triangleBucketA      = new Triangle3D[processedTriCount];
            Triangle3D[] triangleBucketB      = new Triangle3D[processedTriCount];
            for (int i = 0; i < processedTriCount; i++)
            {
                ClassificationUtil.Classification[] classes;
                ClassificationUtil.Classification   triClass = ClassificationUtil.ClassifyPoints(processedTris[i].pos, cuttingPlane, out classes, epsilon);

                if (triClass == ClassificationUtil.Classification.FRONT)
                {
                    triangleBucketA[triangleBucketACount++] = processedTris[i];
                }

                else if (triClass == ClassificationUtil.Classification.BACK)
                {
                    triangleBucketB[triangleBucketBCount++] = processedTris[i];
                }
            }

            if (triangleBucketACount == 0 || triangleBucketBCount == 0)
            {
                return(false);
            }

            List <Triangle3D>        totalCapTriBucket  = new List <Triangle3D>();
            List <Triangle3D.Vertex> totalCapVertBucket = new List <Triangle3D.Vertex>();

            while (cap && debugEdges.Count > 2)
            {
                List <Triangle3D>        capTriBucket  = new List <Triangle3D>();
                List <Triangle3D.Vertex> capVertBucket = new List <Triangle3D.Vertex>();

                Triangle3D.Vertex[] sortedVerts = GetPolyLoop(ref debugEdges);

                if (sortedVerts != null)
                {
                    CapMesh(out capTriBucket, out capVertBucket, sortedVerts, transform, rotation, totalCapTriBucket.Count);
                }

                if (capVertBucket.Count > 2)
                {
                    for (int i = 0; i < capVertBucket.Count - 1; i++)
                    {
                        Debug.DrawLine(transform.TransformPoint(capVertBucket[i].pos), transform.TransformPoint(capVertBucket[i + 1].pos));
                    }
                    Debug.DrawLine(transform.TransformPoint(capVertBucket[capVertBucket.Count - 1].pos), transform.TransformPoint(capVertBucket[0].pos));
                }

                totalCapTriBucket.AddRange(capTriBucket);
                totalCapVertBucket.AddRange(capVertBucket);
            }

            if (triangleBucketACount > 0)
            {
                SortMesh(outputMeshes[0], triangleBucketA, triangleBucketACount, transform, totalCapTriBucket, totalCapVertBucket, false);
            }
            if (triangleBucketBCount > 0)
            {
                SortMesh(outputMeshes[1], triangleBucketB, triangleBucketBCount, transform, totalCapTriBucket, totalCapVertBucket, true);
            }
            return(true);
        }

        else
        {
            Debug.Log("source geometry empty");
            return(false);
        }
    }
    public static Triangle3D[] SplitTriangleWithPlane(Triangle3D triangle, Plane plane, float e, out ClassificationUtil.Classification side, bool cap)
    {
        ClassificationUtil.Classification[] classes;
        side = ClassificationUtil.ClassifyTriangle(triangle, plane, out classes, e);

        if(side != ClassificationUtil.Classification.STRADDLE)
        {
            if(cap)
            {
                SetEdge(0, 1, classes, triangle.pos);
                SetEdge(1, 2, classes, triangle.pos);
                SetEdge(2, 0, classes, triangle.pos);
            }
            return null;
        }

        //int iA;
        Triangle3D.Vertex pA;
        Vector3 normA;
        Vector2 uvA;
        //Vector4 tA;

        uint aLength = 0;
        int[] indicesA = new int[4];
        Triangle3D.Vertex[] verticesA = new Triangle3D.Vertex[4];
        Vector3[] normalsA = new Vector3[4];
        Vector2[] uvsA = new Vector2[4];
        Vector4[] tangentsA = new Vector4[4];

        int iB;
        Triangle3D.Vertex pB;
        Vector3 normB;
        Vector2 uvB;
        Vector4 tB;

        uint bLength = 0;
        int[] indicesB = new int[4];
        Triangle3D.Vertex[] verticesB = new Triangle3D.Vertex[4];
        Vector3[] normalsB = new Vector3[4];
        Vector2[] uvsB = new Vector2[4];
        Vector4[] tangentsB = new Vector4[4];

        float sideA;
        float sideB;
        Intersection isect;
        Vector2 newUV;

        List<Vector3> cVerts = new List<Vector3> ();

        int[] indices = new int[] { triangle.idxV0, triangle.idxV1, triangle.idxV2 };
        Triangle3D.Vertex[] points = new Triangle3D.Vertex[] { triangle.v0, triangle.v1, triangle.v2 };
        Vector3[] normals = new Vector3[] { triangle.nv0, triangle.nv1, triangle.nv2 };
        Vector2[] uvs = new Vector2[] { triangle.uv0, triangle.uv1, triangle.uv2 };
        Vector4[] tangents = new Vector4[] { triangle.tv0, triangle.tv1, triangle.tv2 };

        float[] distance = new float[3];
        for(int i = 0; i < points.Length; i++)
        {
            distance[i] = plane.GetDistanceToPoint(points[i].pos);
        }

        for(int i = 0; i < points.Length; i++)
        {
            int j = (i + 1) % points.Length;

            //iA = indices[i];
            iB = indices[j];

            pA = points[i];
            pB = points[j];

            uvA = uvs[i];
            uvB = uvs[j];

            normA = normals[i];
            normB = normals[j];

            //tA = tangents[i];
            tB = tangents[j];

            sideA = distance[i];
            sideB = distance[j];

            if(sideB > e)
            {
                if(sideA < -e)
                {
                    isect = Intersection.LinePlane(pA.pos, pB.pos, plane, e, null);
                    if(isect.status != Intersection.IntersectionType.INTERSECTION)
                    {
                        plane.distance += Mathf.Epsilon;
                        return SplitTriangleWithPlane(triangle, new Plane (plane.normal, plane.distance + 1.0f), e, out side, cap);
                    }

                    // New vertex was created
                    int newIndex = triangle.meshVertices.Count;
                    triangle.meshVertices.Add(new Triangle3D.Vertex (isect.vert));

                    indicesA[aLength] = newIndex;
                    indicesB[bLength] = newIndex;

                    verticesA[aLength] = new Triangle3D.Vertex (isect.vert);
                    verticesB[bLength] = new Triangle3D.Vertex (isect.vert);

                    newUV = InterpolateUV(uvA, uvB, isect.alpha);
                    uvsA[aLength] = newUV;
                    uvsB[bLength] = newUV;

                    tangentsA[aLength] = tB;
                    tangentsB[bLength] = tB;

                    normalsA[aLength] = Vector3.Lerp(normA, normB, isect.alpha);
                    normalsB[bLength] = Vector3.Lerp(normA, normB, isect.alpha);

                    aLength++;
                    bLength++;

                    if(!cVerts.Contains(isect.vert))
                    {
                        cVerts.Add(isect.vert);
                    }
                }

                indicesA[aLength] = iB;
                verticesA[aLength] = pB;
                uvsA[aLength] = uvB;
                normalsA[aLength] = normB;
                tangentsA[aLength] = tB;

                aLength++;
            }

            else if(sideB < -e)
            {
                if(sideA > e)
                {
                    isect = Intersection.LinePlane(pA.pos, pB.pos, plane, e, null);
                    if(isect.status != Intersection.IntersectionType.INTERSECTION)
                    {
                        return SplitTriangleWithPlane(triangle, new Plane(plane.normal, plane.distance + 1.0f), e, out side, cap);
                    }

                    // New vertex was created
                    int newIndex = triangle.meshVertices.Count;
                    triangle.meshVertices.Add(new Triangle3D.Vertex (isect.vert));

                    indicesA[aLength] = newIndex;
                    indicesB[bLength] = newIndex;

                    verticesA[aLength] = new Triangle3D.Vertex (isect.vert);
                    verticesB[bLength] = new Triangle3D.Vertex (isect.vert);

                    newUV = InterpolateUV(uvA, uvB, isect.alpha);
                    uvsA[aLength] = newUV;
                    uvsB[bLength] = newUV;

                    tangentsA[aLength] = tB;
                    tangentsB[bLength] = tB;

                    normalsA[aLength] = Vector3.Lerp(normA, normB, isect.alpha);
                    normalsB[bLength] = Vector3.Lerp(normA, normB, isect.alpha);

                    aLength++;
                    bLength++;

                    if(!cVerts.Contains(isect.vert))
                    {
                        cVerts.Add(isect.vert);
                    }
                }

                indicesB[bLength] = iB;
                verticesB[bLength] = pB;
                uvsB[bLength] = uvB;
                normalsB[bLength] = normB;
                tangentsB[bLength] = tB;

                bLength++;
            }
            else
            {
                indicesA[aLength] = iB;
                verticesA[aLength] = pB;
                uvsA[aLength] = uvB;
                normalsA[aLength] = normB;
                tangentsA[aLength] = tB;

                aLength++;

                indicesB[bLength] = iB;
                verticesB[bLength] = pB;
                uvsB[bLength] = uvB;
                normalsB[bLength] = normB;
                tangentsB[bLength] = tB;

                bLength++;

                cVerts.Add(pB.pos);

                if(!cVerts.Contains(pB.pos))
                {
                    cVerts.Add(pB.pos);
                }
            }
        }

        for(int i = 0; i < cVerts.Count - 1; i++)
        {
            MeshSlicer.debugEdges.Add(new Vector3[] { cVerts[i], cVerts[i + 1] });
        }

        Triangle3D[] tris;
        if(aLength > 3 || bLength > 3)
        {
            tris = new Triangle3D[3];
        }

        else
        {
            tris = new Triangle3D[2];
        }

        tris[0] = new Triangle3D (triangle.meshVertices, new Triangle3D.Vertex[] { verticesA[0], verticesA[1], verticesA[2] }, new Vector3[] { normalsA[0], normalsA[1], normalsA[2] }, new Vector2[] { uvsA[0], uvsA[1], uvsA[2] }, new Vector4[] { tangentsA[0], tangentsA[1], tangentsA[2] }, new int[] { indicesA[0], indicesA[1], indicesA[2] }, triangle.subMeshGroup);

        tris[1] = new Triangle3D (triangle.meshVertices, new Triangle3D.Vertex[] { verticesB[0], verticesB[1], verticesB[2] }, new Vector3[] { normalsB[0], normalsB[1], normalsB[2] }, new Vector2[] { uvsB[0], uvsB[1], uvsB[2] }, new Vector4[] { tangentsB[0], tangentsB[1], tangentsB[2] }, new int[] { indicesB[0], indicesB[1], indicesB[2] }, triangle.subMeshGroup);

        if(aLength > 3)
        {
            tris[2] = new Triangle3D (triangle.meshVertices, new Triangle3D.Vertex[] { verticesA[0], verticesA[2], verticesA[3] }, new Vector3[] { normalsA[0], normalsA[2], normalsA[3] }, new Vector2[] { uvsA[0], uvsA[2], uvsA[3] }, new Vector4[] { tangentsA[0], tangentsA[2], tangentsA[3] }, new int[] { indicesA[0], indicesA[2], indicesA[3] }, triangle.subMeshGroup);

        }

        else if(bLength > 3)
        {
            tris[2] = new Triangle3D (triangle.meshVertices, new Triangle3D.Vertex[] { verticesB[0], verticesB[2], verticesB[3] }, new Vector3[] { normalsB[0], normalsB[2], normalsB[3] }, new Vector2[] { uvsB[0], uvsB[2], uvsB[3] }, new Vector4[] { tangentsB[0], tangentsB[2], tangentsB[3] }, new int[] { indicesB[0], indicesB[2], indicesB[3] }, triangle.subMeshGroup);
        }
        return tris;
    }
Exemple #6
0
    public static Triangle3D[] SplitTriangleWithPlane(Triangle3D triangle, Plane plane, float e, out ClassificationUtil.Classification side, bool cap)
    {
        ClassificationUtil.Classification[] classes;
        side = ClassificationUtil.ClassifyTriangle(triangle, plane, out classes, e);


        if (side != ClassificationUtil.Classification.STRADDLE)
        {
            if (cap)
            {
                SetEdge(0, 1, classes, triangle.pos);
                SetEdge(1, 2, classes, triangle.pos);
                SetEdge(2, 0, classes, triangle.pos);
            }
            return(null);
        }

        //int iA;
        Triangle3D.Vertex pA;
        Vector3           normA;
        Vector2           uvA;
        //Vector4 tA;

        uint aLength = 0;

        int[] indicesA = new int[4];
        Triangle3D.Vertex[] verticesA = new Triangle3D.Vertex[4];
        Vector3[]           normalsA  = new Vector3[4];
        Vector2[]           uvsA      = new Vector2[4];
        Vector4[]           tangentsA = new Vector4[4];

        int iB;

        Triangle3D.Vertex pB;
        Vector3           normB;
        Vector2           uvB;
        Vector4           tB;

        uint bLength = 0;

        int[] indicesB = new int[4];
        Triangle3D.Vertex[] verticesB = new Triangle3D.Vertex[4];
        Vector3[]           normalsB  = new Vector3[4];
        Vector2[]           uvsB      = new Vector2[4];
        Vector4[]           tangentsB = new Vector4[4];

        float        sideA;
        float        sideB;
        Intersection isect;
        Vector2      newUV;

        List <Vector3> cVerts = new List <Vector3> ();

        int[] indices = new int[] { triangle.idxV0, triangle.idxV1, triangle.idxV2 };
        Triangle3D.Vertex[] points   = new Triangle3D.Vertex[] { triangle.v0, triangle.v1, triangle.v2 };
        Vector3[]           normals  = new Vector3[] { triangle.nv0, triangle.nv1, triangle.nv2 };
        Vector2[]           uvs      = new Vector2[] { triangle.uv0, triangle.uv1, triangle.uv2 };
        Vector4[]           tangents = new Vector4[] { triangle.tv0, triangle.tv1, triangle.tv2 };

        float[] distance = new float[3];
        for (int i = 0; i < points.Length; i++)
        {
            distance[i] = plane.GetDistanceToPoint(points[i].pos);
        }

        for (int i = 0; i < points.Length; i++)
        {
            int j = (i + 1) % points.Length;

            //iA = indices[i];
            iB = indices[j];

            pA = points[i];
            pB = points[j];

            uvA = uvs[i];
            uvB = uvs[j];

            normA = normals[i];
            normB = normals[j];

            //tA = tangents[i];
            tB = tangents[j];

            sideA = distance[i];
            sideB = distance[j];


            if (sideB > e)
            {
                if (sideA < -e)
                {
                    isect = Intersection.LinePlane(pA.pos, pB.pos, plane, e, null);
                    if (isect.status != Intersection.IntersectionType.INTERSECTION)
                    {
                        plane.distance += Mathf.Epsilon;
                        return(SplitTriangleWithPlane(triangle, new Plane(plane.normal, plane.distance + 1.0f), e, out side, cap));
                    }

                    // New vertex was created
                    int newIndex = triangle.meshVertices.Count;
                    triangle.meshVertices.Add(new Triangle3D.Vertex(isect.vert));

                    indicesA[aLength] = newIndex;
                    indicesB[bLength] = newIndex;

                    verticesA[aLength] = new Triangle3D.Vertex(isect.vert);
                    verticesB[bLength] = new Triangle3D.Vertex(isect.vert);


                    newUV         = InterpolateUV(uvA, uvB, isect.alpha);
                    uvsA[aLength] = newUV;
                    uvsB[bLength] = newUV;

                    tangentsA[aLength] = tB;
                    tangentsB[bLength] = tB;

                    normalsA[aLength] = Vector3.Lerp(normA, normB, isect.alpha);
                    normalsB[bLength] = Vector3.Lerp(normA, normB, isect.alpha);

                    aLength++;
                    bLength++;

                    if (!cVerts.Contains(isect.vert))
                    {
                        cVerts.Add(isect.vert);
                    }
                }

                indicesA[aLength]  = iB;
                verticesA[aLength] = pB;
                uvsA[aLength]      = uvB;
                normalsA[aLength]  = normB;
                tangentsA[aLength] = tB;

                aLength++;
            }

            else if (sideB < -e)
            {
                if (sideA > e)
                {
                    isect = Intersection.LinePlane(pA.pos, pB.pos, plane, e, null);
                    if (isect.status != Intersection.IntersectionType.INTERSECTION)
                    {
                        return(SplitTriangleWithPlane(triangle, new Plane(plane.normal, plane.distance + 1.0f), e, out side, cap));
                    }

                    // New vertex was created
                    int newIndex = triangle.meshVertices.Count;
                    triangle.meshVertices.Add(new Triangle3D.Vertex(isect.vert));

                    indicesA[aLength] = newIndex;
                    indicesB[bLength] = newIndex;

                    verticesA[aLength] = new Triangle3D.Vertex(isect.vert);
                    verticesB[bLength] = new Triangle3D.Vertex(isect.vert);

                    newUV         = InterpolateUV(uvA, uvB, isect.alpha);
                    uvsA[aLength] = newUV;
                    uvsB[bLength] = newUV;

                    tangentsA[aLength] = tB;
                    tangentsB[bLength] = tB;

                    normalsA[aLength] = Vector3.Lerp(normA, normB, isect.alpha);
                    normalsB[bLength] = Vector3.Lerp(normA, normB, isect.alpha);

                    aLength++;
                    bLength++;

                    if (!cVerts.Contains(isect.vert))
                    {
                        cVerts.Add(isect.vert);
                    }
                }

                indicesB[bLength]  = iB;
                verticesB[bLength] = pB;
                uvsB[bLength]      = uvB;
                normalsB[bLength]  = normB;
                tangentsB[bLength] = tB;

                bLength++;
            }
            else
            {
                indicesA[aLength]  = iB;
                verticesA[aLength] = pB;
                uvsA[aLength]      = uvB;
                normalsA[aLength]  = normB;
                tangentsA[aLength] = tB;

                aLength++;

                indicesB[bLength]  = iB;
                verticesB[bLength] = pB;
                uvsB[bLength]      = uvB;
                normalsB[bLength]  = normB;
                tangentsB[bLength] = tB;

                bLength++;

                cVerts.Add(pB.pos);

                if (!cVerts.Contains(pB.pos))
                {
                    cVerts.Add(pB.pos);
                }
            }
        }

        for (int i = 0; i < cVerts.Count - 1; i++)
        {
            MeshSlicer.debugEdges.Add(new Vector3[] { cVerts[i], cVerts[i + 1] });
        }

        Triangle3D[] tris;
        if (aLength > 3 || bLength > 3)
        {
            tris = new Triangle3D[3];
        }

        else
        {
            tris = new Triangle3D[2];
        }

        tris[0] = new Triangle3D(triangle.meshVertices, new Triangle3D.Vertex[] { verticesA[0], verticesA[1], verticesA[2] }, new Vector3[] { normalsA[0], normalsA[1], normalsA[2] }, new Vector2[] { uvsA[0], uvsA[1], uvsA[2] }, new Vector4[] { tangentsA[0], tangentsA[1], tangentsA[2] }, new int[] { indicesA[0], indicesA[1], indicesA[2] }, triangle.subMeshGroup);

        tris[1] = new Triangle3D(triangle.meshVertices, new Triangle3D.Vertex[] { verticesB[0], verticesB[1], verticesB[2] }, new Vector3[] { normalsB[0], normalsB[1], normalsB[2] }, new Vector2[] { uvsB[0], uvsB[1], uvsB[2] }, new Vector4[] { tangentsB[0], tangentsB[1], tangentsB[2] }, new int[] { indicesB[0], indicesB[1], indicesB[2] }, triangle.subMeshGroup);

        if (aLength > 3)
        {
            tris[2] = new Triangle3D(triangle.meshVertices, new Triangle3D.Vertex[] { verticesA[0], verticesA[2], verticesA[3] }, new Vector3[] { normalsA[0], normalsA[2], normalsA[3] }, new Vector2[] { uvsA[0], uvsA[2], uvsA[3] }, new Vector4[] { tangentsA[0], tangentsA[2], tangentsA[3] }, new int[] { indicesA[0], indicesA[2], indicesA[3] }, triangle.subMeshGroup);
        }

        else if (bLength > 3)
        {
            tris[2] = new Triangle3D(triangle.meshVertices, new Triangle3D.Vertex[] { verticesB[0], verticesB[2], verticesB[3] }, new Vector3[] { normalsB[0], normalsB[2], normalsB[3] }, new Vector2[] { uvsB[0], uvsB[2], uvsB[3] }, new Vector4[] { tangentsB[0], tangentsB[2], tangentsB[3] }, new int[] { indicesB[0], indicesB[2], indicesB[3] }, triangle.subMeshGroup);
        }
        return(tris);
    }