Exemple #1
0
    /// <summary>
    /// 线段与面的交点
    /// </summary>
    /// <param name="plane"></param>
    /// <param name="segmentStartPoint"></param>
    /// <param name="segmentEndPoint"></param>
    /// <returns></returns>
    public static bool GetSegmentPlaneIntersectionPoint(this Plane plane, Vector3 segmentStartPoint, Vector3 segmentEndPoint, out Vector3 intersectionPoint)
    {
        intersectionPoint = default(Vector3);

        SideOfPlane point0Side = PointSideOfPlane(plane, segmentStartPoint);
        SideOfPlane point1Side = PointSideOfPlane(plane, segmentEndPoint);

        if (point0Side == point1Side)
        {
            return(false);
        }

        return(GetRayPlaneIntersectionPoint(plane, segmentStartPoint, segmentEndPoint, out intersectionPoint));
    }
        /**
         * Slice the gameobject mesh (if any) using the Plane, which will generate
         * a maximum of 2 other Meshes.
         * This function will recalculate new UV coordinates to ensure textures are applied
         * properly.
         * Returns null if no intersection has been found or the GameObject does not contain
         * a valid mesh to cut.
         */
        public static SlicedHull Slice(Mesh sharedMesh, Plane pl, bool genCrossSection = true)
        {
            if (sharedMesh == null)
            {
                return(null);
            }

            Vector3[] verts = sharedMesh.vertices;
            Vector2[] uv    = sharedMesh.uv;
            Vector3[] norm  = sharedMesh.normals;
            Vector4[] tan   = sharedMesh.tangents;

            int submeshCount = sharedMesh.subMeshCount;

            // each submesh will be sliced and placed in its own array structure
            SlicedSubmesh[] slices = new SlicedSubmesh[submeshCount];
            // the cross section hull is common across all submeshes
            List <Vector3> crossHull = new List <Vector3>();

            // we reuse this object for all intersection tests
            IntersectionResult result = new IntersectionResult();

            // see if we would like to split the mesh using uv, normals and tangents
            bool genUV   = verts.Length == uv.Length;
            bool genNorm = verts.Length == norm.Length;
            bool genTan  = verts.Length == tan.Length;

            // iterate over all the submeshes individually. vertices and indices
            // are all shared within the submesh
            for (int submesh = 0; submesh < submeshCount; submesh++)
            {
                int[] indices      = sharedMesh.GetTriangles(submesh);
                int   indicesCount = indices.Length;

                SlicedSubmesh mesh = new SlicedSubmesh();

                // loop through all the mesh vertices, generating upper and lower hulls
                // and all intersection points
                for (int index = 0; index < indicesCount; index += 3)
                {
                    int i0 = indices[index + 0];
                    int i1 = indices[index + 1];
                    int i2 = indices[index + 2];

                    Triangle newTri = new Triangle(verts[i0], verts[i1], verts[i2]);

                    // generate UV if available
                    if (genUV)
                    {
                        newTri.SetUV(uv[i0], uv[i1], uv[i2]);
                    }

                    // generate normals if available
                    if (genNorm)
                    {
                        newTri.SetNormal(norm[i0], norm[i1], norm[i2]);
                    }

                    // generate tangents if available
                    if (genTan)
                    {
                        newTri.SetTangent(tan[i0], tan[i1], tan[i2]);
                    }

                    // slice this particular triangle with the provided
                    // plane
                    if (newTri.Split(pl, result))
                    {
                        int upperHullCount = result.upperHullCount;
                        int lowerHullCount = result.lowerHullCount;
                        int interHullCount = result.intersectionPointCount;

                        for (int i = 0; i < upperHullCount; i++)
                        {
                            mesh.upperHull.Add(result.upperHull[i]);
                        }

                        for (int i = 0; i < lowerHullCount; i++)
                        {
                            mesh.lowerHull.Add(result.lowerHull[i]);
                        }

                        for (int i = 0; i < interHullCount; i++)
                        {
                            crossHull.Add(result.intersectionPoints[i]);
                        }
                    }
                    else
                    {
                        SideOfPlane side = pl.SideOf(verts[i0]);

                        if (side == SideOfPlane.UP || side == SideOfPlane.ON)
                        {
                            mesh.upperHull.Add(newTri);
                        }
                        else
                        {
                            mesh.lowerHull.Add(newTri);
                        }
                    }
                }

                // register into the index
                slices[submesh] = mesh;
            }

            return(CreateFrom(slices, CreateFrom(crossHull, pl.normal)));
        }
        /**
         * Perform an intersection between Plane and Triangle. This is a comprehensive function
         * which alwo builds a HULL Hirearchy useful for decimation projects. This obviously
         * comes at the cost of more complex code and runtime checks, but the returned results
         * are much more flexible.
         * Results will be filled into the IntersectionResult reference. Check result.isValid()
         * for the final results.
         */
        public static void Intersect(Plane pl, Triangle tri, ref IntersectionResult result)
        {
            // clear the previous results from the IntersectionResult
            result.Clear();

            // grab local variables for easier access
            Vector3 a = tri.positionA;
            Vector3 b = tri.positionB;
            Vector3 c = tri.positionC;

            // check to see which side of the plane the points all
            // lay in. SideOf operation is a simple dot product and some comparison
            // operations, so these are a very quick checks
            SideOfPlane sa = pl.SideOf(a);
            SideOfPlane sb = pl.SideOf(b);
            SideOfPlane sc = pl.SideOf(c);

            // we cannot intersect if the triangle points all fall on the same side
            // of the plane. This is an easy early out test as no intersections are possible.
            if (sa == sb && sb == sc)
            {
                return;
            }

            // detect cases where two points lay straight on the plane, meaning
            // that the plane is actually parralel with one of the edges of the triangle
            else if ((sa == SideOfPlane.ON && sa == sb) ||
                     (sa == SideOfPlane.ON && sa == sc) ||
                     (sb == SideOfPlane.ON && sb == sc))
            {
                return;
            }

            // keep in mind that intersection points are shared by both
            // the upper HULL and lower HULL hence they lie perfectly
            // on the plane that cut them
            Vector3 qa;
            Vector3 qb;

            // check the cases where the points of the triangle actually lie on the plane itself
            // in these cases, there is only going to be 2 triangles, one for the upper HULL and
            // the other on the lower HULL
            // we just need to figure out which points to accept into the upper or lower hulls.
            if (sa == SideOfPlane.ON)
            {
                // if the point a is on the plane, test line b-c
                if (Intersector.Intersect(pl, b, c, out qa))
                {
                    // line b-c intersected, construct out triangles and return approprietly
                    result.AddIntersectionPoint(qa);
                    result.AddIntersectionPoint(a);

                    // our two generated triangles, we need to figure out which
                    // triangle goes into the UPPER hull and which goes into the LOWER hull
                    Triangle ta = new Triangle(a, b, qa);
                    Triangle tb = new Triangle(a, qa, c);

                    // generate UV coordinates if there is any
                    if (tri.hasUV)
                    {
                        // the computed UV coordinate if the intersection point
                        Vector2 pq = tri.GenerateUV(qa);
                        Vector2 pa = tri.uvA;
                        Vector2 pb = tri.uvB;
                        Vector2 pc = tri.uvC;

                        ta.SetUV(pa, pb, pq);
                        tb.SetUV(pa, pq, pc);
                    }

                    // generate Normal coordinates if there is any
                    if (tri.hasNormal)
                    {
                        // the computed Normal coordinate if the intersection point
                        Vector3 pq = tri.GenerateNormal(qa);
                        Vector3 pa = tri.normalA;
                        Vector3 pb = tri.normalB;
                        Vector3 pc = tri.normalC;

                        ta.SetNormal(pa, pb, pq);
                        tb.SetNormal(pa, pq, pc);
                    }

                    // generate Tangent coordinates if there is any
                    if (tri.hasTangent)
                    {
                        // the computed Tangent coordinate if the intersection point
                        Vector4 pq = tri.GenerateTangent(qa);
                        Vector4 pa = tri.tangentA;
                        Vector4 pb = tri.tangentB;
                        Vector4 pc = tri.tangentC;

                        ta.SetTangent(pa, pb, pq);
                        tb.SetTangent(pa, pq, pc);
                    }

                    // b point lies on the upside of the plane
                    if (sb == SideOfPlane.UP)
                    {
                        result.AddUpperHull(ta).AddLowerHull(tb);
                    }

                    // b point lies on the downside of the plane
                    else if (sb == SideOfPlane.DOWN)
                    {
                        result.AddUpperHull(tb).AddLowerHull(ta);
                    }
                }
            }

            // test the case where the b point lies on the plane itself
            else if (sb == SideOfPlane.ON)
            {
                // if the point b is on the plane, test line a-c
                if (Intersector.Intersect(pl, a, c, out qa))
                {
                    // line a-c intersected, construct out triangles and return approprietly
                    result.AddIntersectionPoint(qa);
                    result.AddIntersectionPoint(b);

                    // our two generated triangles, we need to figure out which
                    // triangle goes into the UPPER hull and which goes into the LOWER hull
                    Triangle ta = new Triangle(a, b, qa);
                    Triangle tb = new Triangle(qa, b, c);

                    // generate UV coordinates if there is any
                    if (tri.hasUV)
                    {
                        // the computed UV coordinate if the intersection point
                        Vector2 pq = tri.GenerateUV(qa);
                        Vector2 pa = tri.uvA;
                        Vector2 pb = tri.uvB;
                        Vector2 pc = tri.uvC;

                        ta.SetUV(pa, pb, pq);
                        tb.SetUV(pq, pb, pc);
                    }

                    // generate Normal coordinates if there is any
                    if (tri.hasNormal)
                    {
                        // the computed Normal coordinate if the intersection point
                        Vector3 pq = tri.GenerateNormal(qa);
                        Vector3 pa = tri.normalA;
                        Vector3 pb = tri.normalB;
                        Vector3 pc = tri.normalC;

                        ta.SetNormal(pa, pb, pq);
                        tb.SetNormal(pq, pb, pc);
                    }

                    // generate Tangent coordinates if there is any
                    if (tri.hasTangent)
                    {
                        // the computed Tangent coordinate if the intersection point
                        Vector4 pq = tri.GenerateTangent(qa);
                        Vector4 pa = tri.tangentA;
                        Vector4 pb = tri.tangentB;
                        Vector4 pc = tri.tangentC;

                        ta.SetTangent(pa, pb, pq);
                        tb.SetTangent(pq, pb, pc);
                    }

                    // a point lies on the upside of the plane
                    if (sa == SideOfPlane.UP)
                    {
                        result.AddUpperHull(ta).AddLowerHull(tb);
                    }

                    // a point lies on the downside of the plane
                    else if (sa == SideOfPlane.DOWN)
                    {
                        result.AddUpperHull(tb).AddLowerHull(ta);
                    }
                }
            }

            // test the case where the c point lies on the plane itself
            else if (sc == SideOfPlane.ON)
            {
                // if the point c is on the plane, test line a-b
                if (Intersector.Intersect(pl, a, b, out qa))
                {
                    // line a-c intersected, construct out triangles and return approprietly
                    result.AddIntersectionPoint(qa);
                    result.AddIntersectionPoint(c);

                    // our two generated triangles, we need to figure out which
                    // triangle goes into the UPPER hull and which goes into the LOWER hull
                    Triangle ta = new Triangle(a, qa, c);
                    Triangle tb = new Triangle(qa, b, c);

                    // generate UV coordinates if there is any
                    if (tri.hasUV)
                    {
                        // the computed UV coordinate if the intersection point
                        Vector2 pq = tri.GenerateUV(qa);
                        Vector2 pa = tri.uvA;
                        Vector2 pb = tri.uvB;
                        Vector2 pc = tri.uvC;

                        ta.SetUV(pa, pq, pc);
                        tb.SetUV(pq, pb, pc);
                    }

                    // generate Normal coordinates if there is any
                    if (tri.hasNormal)
                    {
                        // the computed Normal coordinate if the intersection point
                        Vector3 pq = tri.GenerateNormal(qa);
                        Vector3 pa = tri.normalA;
                        Vector3 pb = tri.normalB;
                        Vector3 pc = tri.normalC;

                        ta.SetNormal(pa, pq, pc);
                        tb.SetNormal(pq, pb, pc);
                    }

                    // generate Tangent coordinates if there is any
                    if (tri.hasTangent)
                    {
                        // the computed Tangent coordinate if the intersection point
                        Vector4 pq = tri.GenerateTangent(qa);
                        Vector4 pa = tri.tangentA;
                        Vector4 pb = tri.tangentB;
                        Vector4 pc = tri.tangentC;

                        ta.SetTangent(pa, pq, pc);
                        tb.SetTangent(pq, pb, pc);
                    }

                    // a point lies on the upside of the plane
                    if (sa == SideOfPlane.UP)
                    {
                        result.AddUpperHull(ta).AddLowerHull(tb);
                    }

                    // a point lies on the downside of the plane
                    else if (sa == SideOfPlane.DOWN)
                    {
                        result.AddUpperHull(tb).AddLowerHull(ta);
                    }
                }
            }

            // at this point, all edge cases have been tested and failed, we need to perform
            // full intersection tests against the lines. From this point onwards we will generate
            // 3 triangles
            else if (sa != sb && Intersector.Intersect(pl, a, b, out qa))
            {
                // intersection found against a - b
                result.AddIntersectionPoint(qa);

                // since intersection was found against a - b, we need to check which other
                // lines to check (we only need to check one more line) for intersection.
                // the line we check against will be the line against the point which lies on
                // the other side of the plane.
                if (sa == sc)
                {
                    // we likely have an intersection against line b-c which will complete this loop
                    if (Intersector.Intersect(pl, b, c, out qb))
                    {
                        result.AddIntersectionPoint(qb);

                        // our three generated triangles. Two of these triangles will end
                        // up on either the UPPER or LOWER hulls.
                        Triangle ta = new Triangle(qa, b, qb);
                        Triangle tb = new Triangle(a, qa, qb);
                        Triangle tc = new Triangle(a, qb, c);

                        // generate UV coordinates if there is any
                        if (tri.hasUV)
                        {
                            // the computed UV coordinate if the intersection point
                            Vector2 pqa = tri.GenerateUV(qa);
                            Vector2 pqb = tri.GenerateUV(qb);
                            Vector2 pa  = tri.uvA;
                            Vector2 pb  = tri.uvB;
                            Vector2 pc  = tri.uvC;

                            ta.SetUV(pqa, pb, pqb);
                            tb.SetUV(pa, pqa, pqb);
                            tc.SetUV(pa, pqb, pc);
                        }

                        // generate Normal coordinates if there is any
                        if (tri.hasNormal)
                        {
                            // the computed Normal coordinate if the intersection point
                            Vector3 pqa = tri.GenerateNormal(qa);
                            Vector3 pqb = tri.GenerateNormal(qb);
                            Vector3 pa  = tri.normalA;
                            Vector3 pb  = tri.normalB;
                            Vector3 pc  = tri.normalC;

                            ta.SetNormal(pqa, pb, pqb);
                            tb.SetNormal(pa, pqa, pqb);
                            tc.SetNormal(pa, pqb, pc);
                        }

                        // generate Tangent coordinates if there is any
                        if (tri.hasTangent)
                        {
                            // the computed Tangent coordinate if the intersection point
                            Vector4 pqa = tri.GenerateTangent(qa);
                            Vector4 pqb = tri.GenerateTangent(qb);
                            Vector4 pa  = tri.tangentA;
                            Vector4 pb  = tri.tangentB;
                            Vector4 pc  = tri.tangentC;

                            ta.SetTangent(pqa, pb, pqb);
                            tb.SetTangent(pa, pqa, pqb);
                            tc.SetTangent(pa, pqb, pc);
                        }

                        if (sa == SideOfPlane.UP)
                        {
                            result.AddUpperHull(tb).AddUpperHull(tc).AddLowerHull(ta);
                        }
                        else
                        {
                            result.AddLowerHull(tb).AddLowerHull(tc).AddUpperHull(ta);
                        }
                    }
                }
                else
                {
                    // in this scenario, the point a is a "lone" point which lies in either upper
                    // or lower HULL. We need to perform another intersection to find the last point
                    if (Intersector.Intersect(pl, a, c, out qb))
                    {
                        result.AddIntersectionPoint(qb);

                        // our three generated triangles. Two of these triangles will end
                        // up on either the UPPER or LOWER hulls.
                        Triangle ta = new Triangle(a, qa, qb);
                        Triangle tb = new Triangle(qa, b, c);
                        Triangle tc = new Triangle(qb, qa, c);

                        // generate UV coordinates if there is any
                        if (tri.hasUV)
                        {
                            // the computed UV coordinate if the intersection point
                            Vector2 pqa = tri.GenerateUV(qa);
                            Vector2 pqb = tri.GenerateUV(qb);
                            Vector2 pa  = tri.uvA;
                            Vector2 pb  = tri.uvB;
                            Vector2 pc  = tri.uvC;

                            ta.SetUV(pa, pqa, pqb);
                            tb.SetUV(pqa, pb, pc);
                            tc.SetUV(pqb, pqa, pc);
                        }

                        // generate Normal coordinates if there is any
                        if (tri.hasNormal)
                        {
                            // the computed Normal coordinate if the intersection point
                            Vector3 pqa = tri.GenerateNormal(qa);
                            Vector3 pqb = tri.GenerateNormal(qb);
                            Vector3 pa  = tri.normalA;
                            Vector3 pb  = tri.normalB;
                            Vector3 pc  = tri.normalC;

                            ta.SetNormal(pa, pqa, pqb);
                            tb.SetNormal(pqa, pb, pc);
                            tc.SetNormal(pqb, pqa, pc);
                        }

                        // generate Tangent coordinates if there is any
                        if (tri.hasTangent)
                        {
                            // the computed Tangent coordinate if the intersection point
                            Vector4 pqa = tri.GenerateTangent(qa);
                            Vector4 pqb = tri.GenerateTangent(qb);
                            Vector4 pa  = tri.tangentA;
                            Vector4 pb  = tri.tangentB;
                            Vector4 pc  = tri.tangentC;

                            ta.SetTangent(pa, pqa, pqb);
                            tb.SetTangent(pqa, pb, pc);
                            tc.SetTangent(pqb, pqa, pc);
                        }

                        if (sa == SideOfPlane.UP)
                        {
                            result.AddUpperHull(ta).AddLowerHull(tb).AddLowerHull(tc);
                        }
                        else
                        {
                            result.AddLowerHull(ta).AddUpperHull(tb).AddUpperHull(tc);
                        }
                    }
                }
            }

            // if line a-b did not intersect (or the lie on the same side of the plane)
            // this simplifies the problem a fair bit. This means we have an intersection
            // in line a-c and b-c, which we can use to build a new UPPER and LOWER hulls
            // we are expecting both of these intersection tests to pass, otherwise something
            // went wrong (float errors? missed a checked case?)
            else if (Intersector.Intersect(pl, c, a, out qa) && Intersector.Intersect(pl, c, b, out qb))
            {
                // in here we know that line a-b actually lie on the same side of the plane, this will
                // simplify the rest of the logic. We also have our intersection points
                // the computed UV coordinate of the intersection point

                result.AddIntersectionPoint(qa);
                result.AddIntersectionPoint(qb);

                // our three generated triangles. Two of these triangles will end
                // up on either the UPPER or LOWER hulls.
                Triangle ta = new Triangle(qa, qb, c);
                Triangle tb = new Triangle(a, qb, qa);
                Triangle tc = new Triangle(a, b, qb);

                // generate UV coordinates if there is any
                if (tri.hasUV)
                {
                    // the computed UV coordinate if the intersection point
                    Vector2 pqa = tri.GenerateUV(qa);
                    Vector2 pqb = tri.GenerateUV(qb);
                    Vector2 pa  = tri.uvA;
                    Vector2 pb  = tri.uvB;
                    Vector2 pc  = tri.uvC;

                    ta.SetUV(pqa, pqb, pc);
                    tb.SetUV(pa, pqb, pqa);
                    tc.SetUV(pa, pb, pqb);
                }

                // generate Normal coordinates if there is any
                if (tri.hasNormal)
                {
                    // the computed Normal coordinate if the intersection point
                    Vector3 pqa = tri.GenerateNormal(qa);
                    Vector3 pqb = tri.GenerateNormal(qb);
                    Vector3 pa  = tri.normalA;
                    Vector3 pb  = tri.normalB;
                    Vector3 pc  = tri.normalC;

                    ta.SetNormal(pqa, pqb, pc);
                    tb.SetNormal(pa, pqb, pqa);
                    tc.SetNormal(pa, pb, pqb);
                }

                // generate Tangent coordinates if there is any
                if (tri.hasTangent)
                {
                    // the computed Tangent coordinate if the intersection point
                    Vector4 pqa = tri.GenerateTangent(qa);
                    Vector4 pqb = tri.GenerateTangent(qb);
                    Vector4 pa  = tri.tangentA;
                    Vector4 pb  = tri.tangentB;
                    Vector4 pc  = tri.tangentC;

                    ta.SetTangent(pqa, pqb, pc);
                    tb.SetTangent(pa, pqb, pqa);
                    tc.SetTangent(pa, pb, pqb);
                }

                if (sa == SideOfPlane.UP)
                {
                    result.AddUpperHull(tb).AddUpperHull(tc).AddLowerHull(ta);
                }
                else
                {
                    result.AddLowerHull(tb).AddLowerHull(tc).AddUpperHull(ta);
                }
            }
        }
Exemple #4
0
        /**
         * Slice the gameobject mesh (if any) using the Plane, which will generate
         * a maximum of 2 other Meshes.
         * This function will recalculate new UV coordinates to ensure textures are applied
         * properly.
         * Returns null if no intersection has been found or the GameObject does not contain
         * a valid mesh to cut.
         */
        public static SlicedHull Slice(Mesh sharedMesh, Plane pl, TextureRegion region, int crossIndex)
        {
            if (sharedMesh == null)
            {
                return(null);
            }

            Vector3[] verts = sharedMesh.vertices;
            Vector2[] uv    = sharedMesh.uv;
            Vector3[] norm  = sharedMesh.normals;
            Vector4[] tan   = sharedMesh.tangents;

            int submeshCount = sharedMesh.subMeshCount;

            // each submesh will be sliced and placed in its own array structure
            SlicedSubmesh[] slices = new SlicedSubmesh[submeshCount];
            // the cross section hull is common across all submeshes
            List <Vector3> crossHull = new List <Vector3>();

            // we reuse this object for all intersection tests
            IntersectionResult result = new IntersectionResult();

            // see if we would like to split the mesh using uv, normals and tangents
            bool genUV   = verts.Length == uv.Length;
            bool genNorm = verts.Length == norm.Length;
            bool genTan  = verts.Length == tan.Length;

            // iterate over all the submeshes individually. vertices and indices
            // are all shared within the submesh
            for (int submesh = 0; submesh < submeshCount; submesh++)
            {
                int[] indices      = sharedMesh.GetTriangles(submesh);
                int   indicesCount = indices.Length;

                SlicedSubmesh mesh = new SlicedSubmesh();

                // loop through all the mesh vertices, generating upper and lower hulls
                // and all intersection points
                for (int index = 0; index < indicesCount; index += 3)
                {
                    int i0 = indices[index + 0];
                    int i1 = indices[index + 1];
                    int i2 = indices[index + 2];

                    Triangle newTri = new Triangle(verts[i0], verts[i1], verts[i2]);

                    // generate UV if available
                    if (genUV)
                    {
                        newTri.SetUV(uv[i0], uv[i1], uv[i2]);
                    }

                    // generate normals if available
                    if (genNorm)
                    {
                        newTri.SetNormal(norm[i0], norm[i1], norm[i2]);
                    }

                    // generate tangents if available
                    if (genTan)
                    {
                        newTri.SetTangent(tan[i0], tan[i1], tan[i2]);
                    }

                    // slice this particular triangle with the provided
                    // plane
                    if (newTri.Split(pl, result))
                    {
                        int upperHullCount = result.upperHullCount;
                        int lowerHullCount = result.lowerHullCount;
                        int interHullCount = result.intersectionPointCount;

                        for (int i = 0; i < upperHullCount; i++)
                        {
                            mesh.upperHull.Add(result.upperHull[i]);
                        }

                        for (int i = 0; i < lowerHullCount; i++)
                        {
                            mesh.lowerHull.Add(result.lowerHull[i]);
                        }

                        for (int i = 0; i < interHullCount; i++)
                        {
                            crossHull.Add(result.intersectionPoints[i]);
                        }
                    }
                    else
                    {
                        SideOfPlane sa = pl.SideOf(verts[i0]);
                        SideOfPlane sb = pl.SideOf(verts[i1]);
                        SideOfPlane sc = pl.SideOf(verts[i2]);

                        SideOfPlane side = SideOfPlane.ON;
                        if (sa != SideOfPlane.ON)
                        {
                            side = sa;
                        }

                        if (sb != SideOfPlane.ON)
                        {
                            Debug.Assert(side == SideOfPlane.ON || side == sb);
                            side = sb;
                        }

                        if (sc != SideOfPlane.ON)
                        {
                            Debug.Assert(side == SideOfPlane.ON || side == sc);
                            side = sc;
                        }

                        if (side == SideOfPlane.UP || side == SideOfPlane.ON)
                        {
                            mesh.upperHull.Add(newTri);
                        }
                        else
                        {
                            mesh.lowerHull.Add(newTri);
                        }
                    }
                }

                // register into the index
                slices[submesh] = mesh;
            }

            // check if slicing actually occured
            for (int i = 0; i < slices.Length; i++)
            {
                // check if at least one of the submeshes was sliced. If so, stop checking
                // because we need to go through the generation step
                if (slices[i] != null && slices[i].isValid)
                {
                    return(CreateFrom(slices, CreateFrom(crossHull, pl.normal, region), crossIndex));
                }
            }

            // no slicing occured, just return null to signify
            return(null);
        }
Exemple #5
0
        /**
         * Slice the gameobject mesh (if any) using the Plane, which will generate
         * a maximum of 2 other Meshes.
         * This function will recalculate new UV coordinates to ensure textures are applied
         * properly.
         * Returns null if no intersection has been found or the GameObject does not contain
         * a valid mesh to cut.
         */
        public static SlicedHull Slice(Mesh sharedMesh, Plane pl, bool genCrossSection = true)
        {
            if (sharedMesh == null)
            {
                return(null);
            }

            Vector3[] ve      = sharedMesh.vertices;
            Vector2[] uv      = sharedMesh.uv;
            int[]     indices = sharedMesh.triangles;

            int indicesCount = indices.Length;

            // we reuse this object for all intersection tests
            IntersectionResult result = new IntersectionResult();

            // all our buffers, as Triangles
            List <Triangle> upperHull = new List <Triangle>();
            List <Triangle> lowerHull = new List <Triangle>();
            List <Vector3>  crossHull = new List <Vector3>();

            // loop through all the mesh vertices, generating upper and lower hulls
            // and all intersection points
            for (int index = 0; index < indicesCount; index += 3)
            {
                int i0 = indices[index + 0];
                int i1 = indices[index + 1];
                int i2 = indices[index + 2];

                Triangle newTri = new Triangle(ve[i0], ve[i1], ve[i2], uv[i0], uv[i1], uv[i2]);

                // slice this particular triangle with the provided
                // plane
                if (newTri.Split(pl, result))
                {
                    int upperHullCount = result.upperHullCount;
                    int lowerHullCount = result.lowerHullCount;
                    int interHullCount = result.intersectionPointCount;

                    for (int i = 0; i < upperHullCount; i++)
                    {
                        upperHull.Add(result.upperHull[i]);
                    }

                    for (int i = 0; i < lowerHullCount; i++)
                    {
                        lowerHull.Add(result.lowerHull[i]);
                    }

                    for (int i = 0; i < interHullCount; i++)
                    {
                        crossHull.Add(result.intersectionPoints[i]);
                    }
                }
                else
                {
                    SideOfPlane side = pl.SideOf(ve[i0]);

                    if (side == SideOfPlane.UP || side == SideOfPlane.ON)
                    {
                        upperHull.Add(newTri);
                    }
                    else
                    {
                        lowerHull.Add(newTri);
                    }
                }
            }

            // start creating our hulls
            Mesh finalUpperHull = CreateFrom(upperHull);
            Mesh finalLowerHull = CreateFrom(lowerHull);

            // we need to generate the cross section if set
            // NOTE -> This uses a MonotoneChain algorithm which will only work
            // on cross sections which are Convex
            if (genCrossSection)
            {
                Mesh[] crossSections = CreateFrom(crossHull, pl.normal);

                if (crossSections != null)
                {
                    return(new SlicedHull(finalUpperHull, finalLowerHull, crossSections[0], crossSections[1]));
                }
            }

            return(new SlicedHull(finalUpperHull, finalLowerHull));
        }
Exemple #6
0
    /// <summary>
    /// 获取面与三角形相交结果
    /// </summary>
    /// <param name="plane">平面</param>
    /// <param name="triangle">三角形</param>
    /// <param name="includePlaneBack">是否包括Plane的反面</param>
    /// <returns></returns>
    public static PlaneTriangleIntersectionResult GetPlaneTriangleIntersectionResult(Plane plane, Triangle triangle, bool includePlaneBack = false)
    {
        PlaneTriangleIntersectionResult intersectionResult = new PlaneTriangleIntersectionResult();

        Vector3 p0 = triangle.VertexPosition0;
        Vector3 p1 = triangle.VertexPosition1;
        Vector3 p2 = triangle.VertexPosition2;

        SideOfPlane p0SideOfPlane = plane.PointSideOfPlane(p0);
        SideOfPlane p1SideOfPlane = plane.PointSideOfPlane(p1);
        SideOfPlane p2SideOfPlane = plane.PointSideOfPlane(p2);

        //三个点在同一方向
        if (p0SideOfPlane == p1SideOfPlane && p0SideOfPlane == p2SideOfPlane)
        {
            if (p0SideOfPlane == SideOfPlane.UP)
            {
                intersectionResult.UpperTriangleList.Add(triangle);
            }

            if (includePlaneBack && p0SideOfPlane == SideOfPlane.DOWN)
            {
                intersectionResult.UnderTriangleList.Add(triangle);
            }

            return(intersectionResult);
        }
        //两个点在Plane上
        if ((p0SideOfPlane == SideOfPlane.ON) && p0SideOfPlane == p1SideOfPlane)
        {
            if (p2SideOfPlane == SideOfPlane.UP)
            {
                intersectionResult.UpperTriangleList.Add(triangle);
            }
            else
            {
                if (includePlaneBack)
                {
                    intersectionResult.UnderTriangleList.Add(triangle);
                }
            }
        }
        else if ((p0SideOfPlane == SideOfPlane.ON) && p0SideOfPlane == p2SideOfPlane)
        {
            if (p1SideOfPlane == SideOfPlane.UP)
            {
                intersectionResult.UpperTriangleList.Add(triangle);
            }
            else
            {
                if (includePlaneBack)
                {
                    intersectionResult.UnderTriangleList.Add(triangle);
                }
            }
        }
        else if ((p1SideOfPlane == SideOfPlane.ON) && p1SideOfPlane == p2SideOfPlane)
        {
            if (p0SideOfPlane == SideOfPlane.UP)
            {
                intersectionResult.UpperTriangleList.Add(triangle);
            }
            else
            {
                if (includePlaneBack)
                {
                    intersectionResult.UnderTriangleList.Add(triangle);
                }
            }
        }

        //相交点
        Vector3 intersectionPoint0;
        Vector3 intersectionPoint1;

        //一个点在面上,两个点在两侧
        if (p0SideOfPlane == SideOfPlane.ON)
        {
            //b - c
            if (plane.GetSegmentPlaneIntersectionPoint(p1, p2, out intersectionPoint0))
            {
                //交点的barycentric
                Vector3 barycentricWeight   = PointBarycentricInTriangle(intersectionPoint0, p0, p1, p2);
                Vector2 intersectionPointUV = GetTrianglePointByBarycentricWeight2D(barycentricWeight, triangle.UV0, triangle.UV1, triangle.UV2);

                Triangle triangle1 = new Triangle(p0, p1, intersectionPoint0, triangle.UV0, triangle.UV1, intersectionPointUV);
                Triangle triangle2 = new Triangle(p0, intersectionPoint0, p2, triangle.UV0, intersectionPointUV, triangle.UV1);

                intersectionResult.IntersectionPointList.Add(p0);
                intersectionResult.IntersectionPointList.Add(intersectionPoint0);

                if (p1SideOfPlane == SideOfPlane.UP)
                {
                    intersectionResult.UpperTriangleList.Add(triangle1);

                    if (includePlaneBack)
                    {
                        intersectionResult.UnderTriangleList.Add(triangle2);
                    }
                }
                else
                {
                    intersectionResult.UpperTriangleList.Add(triangle2);

                    if (includePlaneBack)
                    {
                        intersectionResult.UnderTriangleList.Add(triangle1);
                    }
                }
            }
        }
        else if (p1SideOfPlane == SideOfPlane.ON)
        {
            //a - c
            if (plane.GetSegmentPlaneIntersectionPoint(p0, p2, out intersectionPoint0))
            {
                Vector3 barycentricWeight   = PointBarycentricInTriangle(intersectionPoint0, p0, p1, p2);
                Vector2 intersectionPointUV = GetTrianglePointByBarycentricWeight2D(barycentricWeight, triangle.UV0, triangle.UV1, triangle.UV2);

                Triangle triangle1 = new Triangle(p1, intersectionPoint0, p2, triangle.UV1, intersectionPointUV, triangle.UV2);
                Triangle triangle2 = new Triangle(p0, intersectionPoint0, p1, triangle.UV0, intersectionPointUV, triangle.UV1);

                intersectionResult.IntersectionPointList.Add(p1);
                intersectionResult.IntersectionPointList.Add(intersectionPoint0);

                if (p0SideOfPlane == SideOfPlane.UP)
                {
                    intersectionResult.UpperTriangleList.Add(triangle2);

                    if (includePlaneBack)
                    {
                        intersectionResult.UnderTriangleList.Add(triangle1);
                    }
                }
                else
                {
                    intersectionResult.UpperTriangleList.Add(triangle1);

                    if (includePlaneBack)
                    {
                        intersectionResult.UnderTriangleList.Add(triangle2);
                    }
                }
            }
        }
        else if (p2SideOfPlane == SideOfPlane.ON)
        {
            //a - b
            if (plane.GetSegmentPlaneIntersectionPoint(p0, p2, out intersectionPoint0))
            {
                Vector3 barycentricWeight   = PointBarycentricInTriangle(intersectionPoint0, p0, p1, p2);
                Vector2 intersectionPointUV = GetTrianglePointByBarycentricWeight2D(barycentricWeight, triangle.UV0, triangle.UV1, triangle.UV2);

                Triangle triangle1 = new Triangle(p0, intersectionPoint0, p2, triangle.UV0, intersectionPointUV, triangle.UV2);
                Triangle triangle2 = new Triangle(p2, intersectionPoint0, p1, triangle.UV2, intersectionPointUV, triangle.UV1);

                intersectionResult.IntersectionPointList.Add(p2);
                intersectionResult.IntersectionPointList.Add(intersectionPoint0);

                if (p0SideOfPlane == SideOfPlane.UP)
                {
                    intersectionResult.UpperTriangleList.Add(triangle1);

                    if (includePlaneBack)
                    {
                        intersectionResult.UnderTriangleList.Add(triangle2);
                    }
                }
                else
                {
                    intersectionResult.UpperTriangleList.Add(triangle2);

                    if (includePlaneBack)
                    {
                        intersectionResult.UnderTriangleList.Add(triangle1);
                    }
                }
            }
        }
        //a - b
        else if (plane.GetSegmentPlaneIntersectionPoint(p0, p1, out intersectionPoint0))
        {
            Vector3 barycentricWeight0   = PointBarycentricInTriangle(intersectionPoint0, p0, p1, p2);
            Vector2 intersectionPointUV0 = GetTrianglePointByBarycentricWeight2D(barycentricWeight0, triangle.UV0, triangle.UV1, triangle.UV2);

            intersectionResult.IntersectionPointList.Add(intersectionPoint0);

            // b - c
            if (p0SideOfPlane == p2SideOfPlane)
            {
                if (plane.GetSegmentPlaneIntersectionPoint(p1, p2, out intersectionPoint1))
                {
                    Vector3 barycentricWeight1   = PointBarycentricInTriangle(intersectionPoint1, p0, p1, p2);
                    Vector2 intersectionPointUV1 = GetTrianglePointByBarycentricWeight2D(barycentricWeight1, triangle.UV0, triangle.UV1, triangle.UV2);

                    Triangle triangle0 = new Triangle(p0, intersectionPoint0, intersectionPoint1, triangle.UV0, intersectionPointUV0, intersectionPointUV1);
                    Triangle triangle1 = new Triangle(p0, intersectionPoint1, p2, triangle.UV0, intersectionPointUV1, triangle.UV2);
                    Triangle triangle2 = new Triangle(intersectionPoint0, p1, intersectionPoint1, intersectionPointUV0, triangle.UV1, intersectionPointUV1);

                    intersectionResult.IntersectionPointList.Add(intersectionPoint1);

                    if (p0SideOfPlane == SideOfPlane.UP)
                    {
                        intersectionResult.UpperTriangleList.Add(triangle0);
                        intersectionResult.UpperTriangleList.Add(triangle1);

                        if (includePlaneBack)
                        {
                            intersectionResult.UnderTriangleList.Add(triangle2);
                        }
                    }
                    else
                    {
                        intersectionResult.UpperTriangleList.Add(triangle2);

                        if (includePlaneBack)
                        {
                            intersectionResult.UnderTriangleList.Add(triangle0);
                            intersectionResult.UnderTriangleList.Add(triangle1);
                        }
                    }
                }
            }
            //a -c
            else
            {
                if (plane.GetSegmentPlaneIntersectionPoint(p0, p2, out intersectionPoint1))
                {
                    Vector3 barycentricWeight1   = PointBarycentricInTriangle(intersectionPoint1, p0, p1, p2);
                    Vector2 intersectionPointUV1 = GetTrianglePointByBarycentricWeight2D(barycentricWeight1, triangle.UV0, triangle.UV1, triangle.UV2);

                    intersectionResult.IntersectionPointList.Add(intersectionPoint1);

                    Triangle triangle0 = new Triangle(p0, intersectionPoint0, intersectionPoint1, triangle.UV0, intersectionPointUV0, intersectionPointUV1);

                    Triangle triangle1 = new Triangle(intersectionPoint0, p1, p2, intersectionPointUV0, triangle.UV1, triangle.UV2);
                    Triangle triangle2 = new Triangle(intersectionPoint1, intersectionPoint0, p2, intersectionPointUV1, intersectionPointUV0, triangle.UV2);

                    if (p0SideOfPlane == SideOfPlane.UP)
                    {
                        intersectionResult.UpperTriangleList.Add(triangle0);

                        if (includePlaneBack)
                        {
                            intersectionResult.UnderTriangleList.Add(triangle1);
                            intersectionResult.UnderTriangleList.Add(triangle2);
                        }
                    }
                    else
                    {
                        intersectionResult.UpperTriangleList.Add(triangle1);
                        intersectionResult.UpperTriangleList.Add(triangle2);

                        if (includePlaneBack)
                        {
                            intersectionResult.UnderTriangleList.Add(triangle0);
                        }
                    }
                }
            }
        }
        //a-c b -c
        else if (plane.GetSegmentPlaneIntersectionPoint(p0, p2, out intersectionPoint0) && plane.GetSegmentPlaneIntersectionPoint(p1, p2, out intersectionPoint1))
        {
            Vector3 barycentricWeight0   = PointBarycentricInTriangle(intersectionPoint0, p0, p1, p2);
            Vector2 intersectionPointUV0 = GetTrianglePointByBarycentricWeight2D(barycentricWeight0, triangle.UV0, triangle.UV1, triangle.UV2);

            Vector3 barycentricWeight1   = PointBarycentricInTriangle(intersectionPoint1, p0, p1, p2);
            Vector2 intersectionPointUV1 = GetTrianglePointByBarycentricWeight2D(barycentricWeight1, triangle.UV0, triangle.UV1, triangle.UV2);

            intersectionResult.IntersectionPointList.Add(intersectionPoint0);
            intersectionResult.IntersectionPointList.Add(intersectionPoint1);

            Triangle triangle0 = new Triangle(intersectionPoint0, p0, intersectionPoint1, intersectionPointUV0, triangle.UV0, intersectionPointUV1);
            Triangle triangle1 = new Triangle(p0, p1, intersectionPoint1, triangle.UV0, triangle.UV1, intersectionPointUV1);
            Triangle triangle2 = new Triangle(intersectionPoint0, intersectionPoint1, p2, intersectionPointUV0, intersectionPointUV1, triangle.UV2);

            if (p2SideOfPlane == SideOfPlane.UP)
            {
                intersectionResult.UpperTriangleList.Add(triangle2);

                if (includePlaneBack)
                {
                    intersectionResult.UnderTriangleList.Add(triangle0);
                    intersectionResult.UnderTriangleList.Add(triangle1);
                }
            }
            else
            {
                intersectionResult.UpperTriangleList.Add(triangle0);
                intersectionResult.UpperTriangleList.Add(triangle1);

                if (includePlaneBack)
                {
                    intersectionResult.UnderTriangleList.Add(triangle2);
                }
            }
        }

        return(intersectionResult);
    }