Inheritance: MonoBehaviour
Example #1
0
    /// <summary>
    /// 切割模型
    /// </summary>
    /// <param name="includeSection"></param>
    /// <param name="includeOppositeFace"></param>
    /// <param name="remainOrigin">是否保留原始模型</param>
    /// <returns></returns>
    public SlicedMesh Slice(bool includeSection, bool includeOppositeFace)
    {
        this.m_includeSection      = includeSection;
        this.m_includeOppositeFace = includeOppositeFace;

        Mesh sliceMesh = this.m_originMesh;

        GeometryUtility.TriangleWindingOrder meshWindingOrder = GeometryUtility.GetMeshWindingOrder(sliceMesh);
        SlicedMesh slicedMesh = new SlicedMesh(meshWindingOrder);

        for (int j = 0; j < sliceMesh.triangles.Length; j += 3)
        {
            int vertexIndex0 = sliceMesh.triangles[j];
            int vertexIndex1 = sliceMesh.triangles[j + 1];
            int vertexIndex2 = sliceMesh.triangles[j + 2];

            Vector3 vertexPosition0 = sliceMesh.vertices[vertexIndex0];
            Vector3 vertexPosition1 = sliceMesh.vertices[vertexIndex1];
            Vector3 vertexPosition2 = sliceMesh.vertices[vertexIndex2];

            Vector2 uv0 = Vector2.zero;
            Vector2 uv1 = Vector2.zero;
            Vector2 uv2 = Vector2.zero;

            if (sliceMesh.uv.Length != 0)
            {
                uv0 = sliceMesh.uv[vertexIndex0];
                uv1 = sliceMesh.uv[vertexIndex1];
                uv2 = sliceMesh.uv[vertexIndex2];
            }

            GeometryUtility.Triangle triangle = new GeometryUtility.Triangle(vertexPosition0, vertexPosition1, vertexPosition2, uv0, uv1, uv2);
            GeometryUtility.PlaneTriangleIntersectionResult intersectionResult = GeometryUtility.GetPlaneTriangleIntersectionResult(this.m_slicerPlane, triangle, includeOppositeFace);

            slicedMesh.UpperMeshTriangleList.AddRange(intersectionResult.UpperTriangleList);
            slicedMesh.UnderMeshTriangleList.AddRange(intersectionResult.UnderTriangleList);
            slicedMesh.CrossMeshVertexList.AddRange(intersectionResult.IntersectionPointList);
        }

        this.m_slicedUpperMesh = slicedMesh.UpperMesh;

        if (includeOppositeFace)
        {
            this.m_slicedUnderMesh = slicedMesh.UnderMesh;
        }

        //交界处的mesh
        if (includeSection)
        {
            //上交界处的法线是切面的反方向
            this.m_slicedUpperCrossMesh = slicedMesh.GetUpperCrossMesh(m_slicerPlane.normal);

            if (includeOppositeFace)
            {
                this.m_slicedUnderCrossMesh = slicedMesh.GetUnderCrossMesh(m_slicerPlane.normal);
            }
        }

        return(slicedMesh);
    }
Example #2
0
    /// <summary>
    /// 提供方便方法直接切割TriangleList
    /// </summary>
    /// <param name="triangleList"></param>
    /// <param name="includeSection"></param>
    /// <param name="includeOppositeFace"></param>
    /// <returns></returns>
    public static SlicedMesh SliceTriangleList(List <GeometryUtility.Triangle> triangleList, Plane slicerPlane, bool includeSection, bool includeOppositeFace)
    {
        if (triangleList.Count < 1)
        {
            return(null);
        }

        GeometryUtility.TriangleWindingOrder windingOrder = triangleList[0].WindingOrder;
        SlicedMesh slicedMesh = new SlicedMesh(windingOrder);

        for (int i = 0; i < triangleList.Count; ++i)
        {
            GeometryUtility.Triangle sliceTriangle = triangleList[i];
            GeometryUtility.PlaneTriangleIntersectionResult planeTriangleIntersectionResult = GeometryUtility.GetPlaneTriangleIntersectionResult(slicerPlane, sliceTriangle, includeOppositeFace);

            if (!planeTriangleIntersectionResult.IsIntersection)
            {
                continue;
            }

            slicedMesh.UpperMeshTriangleList.AddRange(planeTriangleIntersectionResult.UpperTriangleList);
            if (includeSection)
            {
                slicedMesh.CrossMeshVertexList.AddRange(planeTriangleIntersectionResult.IntersectionPointList);
            }
        }

        return(slicedMesh);
    }
Example #3
0
            override protected void SetSelectionSlicedMeshSizes(SlicedMesh _sliced)
            {
                _sliced.BorderVertical   = 0.5f / transform.lossyScale.z;
                _sliced.BorderHorizontal = 0.5f / transform.lossyScale.x;

                _sliced.Height = 1f + _sliced.BorderVertical * 2f;
                _sliced.Width  = 1f + _sliced.BorderHorizontal * 2f;

                _sliced.MarginVertical   = 0.5f;
                _sliced.MarginHorizontal = 0.5f;
            }
Example #4
0
        virtual protected void SetSelectionSlicedMeshSizes(SlicedMesh _sliced)
        {
            _sliced.BorderVertical   = 0.25f;
            _sliced.BorderHorizontal = 0.25f;

            _sliced.Height = transform.lossyScale.y + _sliced.BorderVertical * 2f;
            _sliced.Width  = transform.lossyScale.x + _sliced.BorderHorizontal * 2f;

            _sliced.MarginVertical   = 0.25f;
            _sliced.MarginHorizontal = 0.25f;
        }
Example #5
0
            override protected void SetSelectionSlicedMeshSizes(SlicedMesh _sliced)
            {
                _sliced.BorderVertical   = 0f;
                _sliced.BorderHorizontal = 0f;

                _sliced.Height = transform.lossyScale.y + 1.0f;
                _sliced.Width  = transform.lossyScale.x + 1.0f;

                _sliced.MarginVertical   = 0f;
                _sliced.MarginHorizontal = 0f;
            }
Example #6
0
    public void Slice()
    {
        //raycast targets forward, might change to multiple casts
        Ray ray = new Ray(transform.position, transform.forward);
        List <RaycastHit> _hits = new List <RaycastHit>();
        //cast a X amount of rays over a Y angle
        float halfAngle = castAngle;

        halfAngle /= 2;

        float minAngle  = -halfAngle;
        float increment = (castAngle / (lines - 1));

        for (float i = minAngle; i <= halfAngle; i += increment)
        {
            Quaternion rayDirection = Quaternion.AngleAxis(i, transform.up);
            Ray        _ray         = new Ray(transform.position, (rayDirection * transform.forward).normalized);
            _hits.AddRange(Physics.RaycastAll(_ray, rayLenght, slicingLayer).ToList());
        }
        //take each first element of the grouped gameobjects, thus distincting them based on object instead of hit
        RaycastHit[] hits = _hits.GroupBy(g => g.transform.gameObject).Select(f => f.First()).ToArray();

        //for all objects that are hit
        for (int h = 0; h < hits.Length; h++)
        {
            Mesh hitMesh             = hits[h].transform.GetComponent <MeshFilter>().mesh;
            List <SlicedMesh> slices = new List <SlicedMesh>();

            SlicedMesh unslicedMesh = new SlicedMesh()
            {
                uv        = hitMesh.uv,
                vertices  = hitMesh.vertices,
                normals   = hitMesh.normals,
                triangles = new int[hitMesh.subMeshCount][],
            };
            for (int i = 0; i < hitMesh.subMeshCount; i++)
            {
                unslicedMesh.triangles[i] = hitMesh.GetTriangles(i);
            }

            //plane with normal up so the plane is parralel to the slice
            Plane plane = new Plane(hits[h].transform.InverseTransformDirection(transform.up), hits[h].transform.InverseTransformPoint(hits[h].point));

            slices.AddRange(GenerateMesh(unslicedMesh, plane, true, hits[h].transform));

            for (int s = 0; s < slices.Count; s++)
            {
                slices[s].MakeGameObject(hits[h].transform.gameObject, sliceMaterial, (s + 1).ToString(), transform.forward * force);
            }
            slices.Clear();
            Destroy(hits[h].transform.gameObject);
        }
    }
Example #7
0
    /// <summary>
    /// 获取贴花的模型
    /// </summary>
    /// <param name="targetMesh"></param>
    /// <param name="targetMeshLocalToWorldMatrix"></param>
    /// <param name="position"></param>
    /// <param name="decalSize"></param>
    /// <param name="rotationEular"></param>
    /// <returns></returns>
    /// todo: 可以根据点基位置估算一个切割顺序,优化,主要基于动态模型切割算法
    public Mesh GetDecalMesh(Mesh targetMesh, Vector3 position, Vector3 decalSize, Vector3 rotationEular, Matrix4x4 projectorCoord)
    {
        Mesh decalMesh = targetMesh;

        //back
        Plane      projectorEdgePlane = GetDecalProjectorEdgePlane(position, rotationEular, decalSize.z, projectorCoord.GetRow(2));
        MeshSlicer slicer             = new MeshSlicer(decalMesh, projectorEdgePlane);

        SlicedMesh slicedMesh = slicer.Slice(false, false);

        if (slicedMesh.UpperMesh == null)
        {
            return(null);
        }

        //left
        projectorEdgePlane = GetDecalProjectorEdgePlane(position, rotationEular, decalSize.x, -projectorCoord.GetRow(0));
        slicedMesh         = MeshSlicer.SliceTriangleList(slicedMesh.UpperMeshTriangleList, projectorEdgePlane, false, false);
        if (slicedMesh == null)
        {
            return(null);
        }

        //right
        projectorEdgePlane = GetDecalProjectorEdgePlane(position, rotationEular, decalSize.x, projectorCoord.GetRow(0));
        slicedMesh         = MeshSlicer.SliceTriangleList(slicedMesh.UpperMeshTriangleList, projectorEdgePlane, false, false);
        if (slicedMesh == null)
        {
            return(null);
        }


        //up
        projectorEdgePlane = GetDecalProjectorEdgePlane(position, rotationEular, decalSize.y, projectorCoord.GetRow(1));
        slicer             = new MeshSlicer(slicedMesh.UpperMesh, projectorEdgePlane);
        slicedMesh         = slicer.Slice(false, false);
        if (slicedMesh.UpperMesh == null)
        {
            return(null);
        }

        //down
        projectorEdgePlane = GetDecalProjectorEdgePlane(position, rotationEular, decalSize.y, -projectorCoord.GetRow(1));
        slicedMesh         = MeshSlicer.SliceTriangleList(slicedMesh.UpperMeshTriangleList, projectorEdgePlane, false, false);
        if (slicedMesh == null)
        {
            return(null);
        }

        return(slicedMesh.UpperMesh);
    }
Example #8
0
    public void Setup(string word, WordManager manager)
    {
        this.word    = word;
        this.manager = manager;

        text = GetComponent <TMP_Text>();
        text.autoSizeTextContainer = true;
        text.text = word;

        backgroundMesh        = GetComponentInChildren <SlicedMesh>();
        backgroundMesh.Width  = text.GetPreferredValues().x + 0.4f;
        backgroundMesh.Height = text.GetPreferredValues().y + 0.2f;
        backgroundMesh.Margin = 0.25f;
        backgroundMesh.transform.Translate(new Vector3(-text.GetPreferredValues().x / 2 - 0.2f, -text.GetPreferredValues().y / 2 - 0.1f, 0));
    }
Example #9
0
    private void AddSliceTriangle(int subMesh, SlicedMesh slice, Vector3 v1, Vector3 v2, Vector3 normal, Vector2 uv1, Vector2 uv2)
    {
        if (!setEdge)
        {
            setEdge    = true;
            edgeVertex = v1;
            edgeUV     = uv1;
        }
        else
        {
            edgePlane.Set3Points(edgeVertex, v1, v2);

            slice.AddTriangle(subMesh,
                              edgeVertex,
                              edgePlane.GetSide(edgeVertex + normal) ? v1 : v2,
                              edgePlane.GetSide(edgeVertex + normal) ? v2 : v1,
                              normal,
                              normal,
                              normal,
                              edgeUV,
                              uv1,
                              uv2);
        }
    }
Example #10
0
    private List <SlicedMesh> GenerateMesh(SlicedMesh original, Plane plane, bool positiveSide, Transform objectTransform)
    {
        SlicedMesh slicePositive = new SlicedMesh();
        SlicedMesh sliceNegative = new SlicedMesh();
        //polygon we use to fill in the sliced surface
        PolygonCreator polygonPositive = new PolygonCreator(objectTransform, plane.normal * -1);
        PolygonCreator polygonNegative = new PolygonCreator(objectTransform, plane.normal);
        bool           matPositiveAdded = false, matNegativeAdded = false;

        //we loop over all submeshes
        for (int submesh = 0; submesh < original.triangles.Length; submesh++)
        {
            int[] originalTriangles = original.triangles[submesh];
            setEdge = false;

            //increase t by 3 because a triangle consist out of 3 vertices;
            for (int t = 0; t < originalTriangles.Length; t += 3)
            {
                //which triangle we need
                int t1 = t, t2 = t + 1, t3 = t + 2;

                //Check if vertice is on positive side of the plane
                bool sideA = plane.GetSide(original.vertices[originalTriangles[t1]]) == positiveSide;
                bool sideB = plane.GetSide(original.vertices[originalTriangles[t2]]) == positiveSide;
                bool sideC = plane.GetSide(original.vertices[originalTriangles[t3]]) == positiveSide;

                //how many vertices are on the positive side of the plane
                int sideCount = (sideA ? 1 : 0) +
                                (sideB ? 1 : 0) +
                                (sideC ? 1 : 0);

                //if none of the vertices is located on the positive side
                if (sideCount == 0)
                {
                    //add entire triangle to negative side
                    sliceNegative.AddTriangle(submesh, original.vertices[originalTriangles[t1]], original.vertices[originalTriangles[t2]], original.vertices[originalTriangles[t3]],
                                              original.normals[originalTriangles[t1]], original.normals[originalTriangles[t2]], original.normals[originalTriangles[t3]],
                                              original.uv[originalTriangles[t1]], original.uv[originalTriangles[t2]], original.uv[originalTriangles[t3]]);
                    if (!matNegativeAdded)
                    {
                        matNegativeAdded = true;
                        sliceNegative.materialIndex.Add(submesh);
                    }

                    continue;
                }
                //if all the vertices are located on the positive side
                else if (sideCount == 3)
                {
                    //add entire triangle to positive side
                    slicePositive.AddTriangle(submesh, original.vertices[originalTriangles[t1]], original.vertices[originalTriangles[t2]], original.vertices[originalTriangles[t3]],
                                              original.normals[originalTriangles[t1]], original.normals[originalTriangles[t2]], original.normals[originalTriangles[t3]],
                                              original.uv[originalTriangles[t1]], original.uv[originalTriangles[t2]], original.uv[originalTriangles[t3]]);
                    if (!matPositiveAdded)
                    {
                        matPositiveAdded = true;
                        slicePositive.materialIndex.Add(submesh);
                    }

                    continue;
                }

                //else a triangle is cut and submesh material must be added to both sides
                if (!matNegativeAdded)
                {
                    matNegativeAdded = true;
                    sliceNegative.materialIndex.Add(submesh);
                }
                if (!matPositiveAdded)
                {
                    matPositiveAdded = true;
                    slicePositive.materialIndex.Add(submesh);
                }


                //determines which vertex in the triangle is solely located on one side of the plane
                int singleIndex = sideB == sideC ? 0 : sideA == sideC ? 1 : 2;
                int indexB = t + ((singleIndex + 1) % 3), indexC = t + ((singleIndex + 2) % 3);
                singleIndex += t;

                //calculate which vertices/normals/uv should be used to calculate intersection points
                Vector3 singleVertex = original.vertices[originalTriangles[singleIndex]],
                        vertexB      = original.vertices[originalTriangles[indexB]],            //right vertex
                        vertexC      = original.vertices[originalTriangles[indexC]];            //left vertex
                Vector3 singleNormal = original.normals[originalTriangles[singleIndex]],
                        normalB      = original.normals[originalTriangles[indexB]],
                        normalC      = original.normals[originalTriangles[indexC]];
                Vector2 singleUv     = original.uv[originalTriangles[singleIndex]],
                        uvB          = original.uv[originalTriangles[indexB]],
                        uvC          = original.uv[originalTriangles[indexC]];

                //calculate new vertices/normals/uv where edge intersects plane
                float   lerpB, lerpC;
                Vector3 newVertexB = PointOnPlane(plane, singleVertex, vertexB, out lerpB),     //new right vertex
                        newVertexC = PointOnPlane(plane, singleVertex, vertexC, out lerpC);     //new left vertex
                Vector3 newNormalB = Vector3.Lerp(singleNormal, normalB, lerpB),                //lerp to get the point between the old vertices where the new vertex is located
                        newNormalC = Vector3.Lerp(singleNormal, normalC, lerpC);
                Vector2 newUvB     = Vector2.Lerp(singleUv, uvB, lerpB),
                        newUvC     = Vector2.Lerp(singleUv, uvC, lerpC);

                if (!concave)
                {
                    //add and edge to "fill" the mesh
                    AddSliceTriangle(submesh, slicePositive, newVertexB, newVertexC,
                                     plane.normal * -1,
                                     newUvB, newUvC);
                    AddSliceTriangle(submesh, sliceNegative, newVertexB, newVertexC,
                                     plane.normal,
                                     newUvB, newUvC);
                }

                if (sideCount == 1)
                {
                    //positive data
                    slicePositive.AddTriangle(submesh, singleVertex, newVertexB, newVertexC, singleNormal, newNormalB, newNormalC, singleUv, newUvB, newUvC);
                    //negative data
                    sliceNegative.AddTriangle(submesh, newVertexB, vertexB, vertexC, newNormalB, normalB, normalC, newUvB, uvB, uvC);
                    sliceNegative.AddTriangle(submesh, newVertexB, vertexC, newVertexC, newNormalB, normalC, newNormalC, newUvB, uvC, newUvC);

                    if (concave)
                    {
                        //positive
                        Edge edgePositive = new Edge(newVertexB, newVertexC, plane.normal * -1, newUvB, newUvC);
                        polygonPositive.AddEdge(edgePositive);
                        //negative
                        Edge edgeNegative = new Edge(newVertexC, newVertexB, plane.normal, newUvC, newUvB);
                        polygonNegative.AddEdge(edgeNegative);
                    }
                    continue;
                }
                else if (sideCount == 2)
                {
                    //positive data
                    slicePositive.AddTriangle(submesh, newVertexB, vertexB, vertexC, newNormalB, normalB, normalC, newUvB, uvB, uvC);
                    slicePositive.AddTriangle(submesh, newVertexB, vertexC, newVertexC, newNormalB, normalC, newNormalC, newUvB, uvC, newUvC);
                    //negative data
                    sliceNegative.AddTriangle(submesh, singleVertex, newVertexB, newVertexC, singleNormal, newNormalB, newNormalC, singleUv, newUvB, newUvC);
                    if (concave)
                    {
                        //positive
                        Edge edgePositive = new Edge(newVertexC, newVertexB, plane.normal * -1, newUvC, newUvB);
                        polygonPositive.AddEdge(edgePositive);
                        //negative
                        Edge edgeNegative = new Edge(newVertexB, newVertexC, plane.normal, newUvB, newUvC);
                        polygonNegative.AddEdge(edgeNegative);
                    }
                    continue;
                }
            }
        }

        if (concave)
        {
            //build polygons
            polygonPositive.ConnectEdges();
            polygonNegative.ConnectEdges();

            //build meshdata for polygons
            FinishedPolygon polygonPositiveFinished = Triangulation.Triangulate(polygonPositive, slicePositive.VertexCount);
            FinishedPolygon polygonNegativeFinished = Triangulation.Triangulate(polygonNegative, sliceNegative.VertexCount);

            //add meshdata to slices
            slicePositive.AddPolygon(polygonPositiveFinished);
            sliceNegative.AddPolygon(polygonNegativeFinished);
        }

        slicePositive.FillArray(correctData);
        sliceNegative.FillArray(correctData);

        return(new List <SlicedMesh>()
        {
            slicePositive, sliceNegative
        });
    }