Unity中Mesh切割的实现(上) | 您所在的位置:网站首页 › unity分割动画 › Unity中Mesh切割的实现(上) |
最近要跟别人联机打无主之地3,忙里抽闲做点东西,避免大脑萎缩。 Mesh的切割做如下思路: 拟定切割的平面求得新增的切割点缝合截面纠正绕序得到新Mesh拟定切割面首先看第一个,拟定切割面。其实这个步骤包含两步,第一步是从输入拿到世界坐标空间下的平面,第二步是把平面从世界坐标空间转到各个模型坐标空间。 先规划好数据类型吧: public struct DividePlane { public Vector3 normal, point; public Vector3 v1, v2, v3; } public struct DivideSegment { public Vector3 p0, p1; public bool available { get { return p0 != p1; } } public DivideSegment(Vector3 v0, Vector3 v1) { p0 = v0; p1 = v1; } }DividePlane之所以要这么设计,是因为一个Plane对不同的模型有着不同的转换后的样式……从输出中拿平面是这样的: private Vector3 pressStart, pressEnd; public List waitForDivide = new List(); private void Update() { if (Input.GetMouseButtonDown(0)) pressStart = Input.mousePosition; if (Input.GetMouseButtonUp(0)) { pressEnd = Input.mousePosition; if (pressEnd == pressStart) return; DividePlane plane = new DividePlane(); plane.v1 = Camera.main.ScreenToWorldPoint(new Vector3(pressStart.x, pressStart.y, Camera.main.nearClipPlane)); plane.v2 = Camera.main.ScreenToWorldPoint(new Vector3(pressEnd.x, pressEnd.y, Camera.main.nearClipPlane)); plane.v3 = Camera.main.ScreenToWorldPoint(new Vector3(pressEnd.x, pressEnd.y, Camera.main.farClipPlane)); for (int i = waitForDivide.Count - 1; i >= 0; i--) if (TransformPlane(waitForDivide[i], ref plane)) { //... } } }然后在转换的过程中,不能先计算法线然后拿去转换,应当把三个点转换好了再Vector3.Cross,这个有必要强调一下,因为以前踩过坑: /// /// DividePlane先转到模型坐标空间下 /// private bool TransformPlane(GameObject toDivide, ref DividePlane plane) { var mf = toDivide.GetComponent(); if (mf == null) return false; var v1 = toDivide.transform.worldToLocalMatrix.MultiplyPoint(plane.v1); var v2 = toDivide.transform.worldToLocalMatrix.MultiplyPoint(plane.v2); var v3 = toDivide.transform.worldToLocalMatrix.MultiplyPoint(plane.v3); plane.point = v2; plane.normal = Vector3.Cross(v3 - v2, v1 - v2).normalized; return true; } 计算面与线段的交点当然,这还是可以划分为两个命题,如何判断线段与面相交,和如何计算这个交点,因为用的点法式表达式,我们可以直接用线段的两端到平面上点的向量与法向量的点积来判断。如果相交的话,必然有两个点积符号相异。 更进一步的,要计算该点的话,就要把线段与平面的交点表达为如下形式: \bold v_{cross}=\bold v_0+k(\bold v_1-\bold v_0)\\ 将平面点法式中的点和法线表达为 \bold P 和 \bold n ,有: (\bold v_{cross}- \bold P) \cdot \bold n = 0\\ 解该方程可得 k ,也就得到交点。 private static bool Intersect(DividePlane plane, DivideSegment segment) { if (!segment.available) return false; Vector3 d0 = segment.p0 - plane.point; Vector3 d1 = segment.p1 - plane.point; float t0 = Vector3.Dot(d0, plane.normal); float t1 = Vector3.Dot(d1, plane.normal); return t0 * t1 缝合截面这一块我暂时没想好,因为思索到了三个问题: 截面上顶点的顺序问题凹多边形如何分配绕序截面可能由多个封闭形状构成且待我之后再细细思索。 生成新Mesh准备好两个新Mesh的容器(当然,可以将旧Mesh所使用的容器认为是其中之一),然后将顶点“倾倒并过滤”。 在这里有个小小的优化,我们新增的顶点绝对是在顶点数组末尾的,因此只需要检查前面的顶点就行: // 检查原Mesh里所有的顶点并分离到左右容器内 for (int i = 0; i = origialVertexCount的顶点而言,必然是后续新增的点 // 即,必然是切面上的点,因此两边都要添加 for (int i = originalVertexCount; i |
CopyRight 2018-2019 实验室设备网 版权所有 |