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