Unity3D中,如果制作者想开发一款类似《水果忍者》类型的游戏,需要利用到Mesh的切割技术,那我认为Ezy-Slice这款插件是必不可少的。本文着重讲解的是如何优化,代码的细节部分我不会过多讲解。有需要的可以自行去官网下载理解。
作者也是第一次写这类技术文章,作为刚入职工作的比较满意的成果,如果有地方写的不好请大家谅解~
首先该插件使用的主要方法入口是SliceObject,需要提供一个被切割的物体GameObject,一个起始的坐标和法线方向,法线方向就是切割完法线朝着的那一侧为正侧,另一侧为反侧。
public SlicedHull SliceObject(GameObject obj, Vector3 StartPosition, Vector3 Normal, Material crossSectionMaterial = null)
{
// slice the provided object using the transforms of this object
return obj.Slice(StartPosition, Normal, crossSectionMaterial);
}
在Slicer类中有这么一个方法
public static SlicedHull Slice(Mesh sharedMesh, Plane pl, TextureRegion region, int crossIndex)
此处将所有的Mesh分为一个个三角面,让每个三角面和入口传入的这个‘片’进行判断是否在正面、侧面、还是相交。相对的,如果两个面有相交,则需要把交点求出。
此处就代码可以进行优化,在制作过程中,原作者并没有把刚刚好共线的线添加到相交的类型里面,导致如果我们切割的时候恰好是沿着这个模型某一条线段进行切割,就会导致缺少这个刚刚好平行的线段,也就是少点了,就无法补足侧面,所以我做了一下的更新。这样就可以把刚刚好是在平面上或者是相交的线段加入到所有相交的点数组中。
if (side == SideOfPlane.UP || side == SideOfPlane.ON)
{
mesh.upperHull.Add(newTri);
if (sa == SideOfPlane.ON && sa == sb)
//如果刚刚好在平面上,直接将线段当作交点加进去
{
result.AddIntersectionPoint(verts[i0]);
result.AddIntersectionPoint(verts[i1]);
}
else if (sa == SideOfPlane.ON && sa == sc)
{
result.AddIntersectionPoint(verts[i0]);
result.AddIntersectionPoint(verts[i2]);
}
else if (sb == SideOfPlane.ON && sb == sc)
{
result.AddIntersectionPoint(verts[i1]);
result.AddIntersectionPoint(verts[i2]);
}
int interHullCount = result.intersectionPointCount;
for (int i = 0; i < interHullCount; i++)
{
var n = result.intersectionPoints[i];
n.i = index + startIndex;
crossHull.Add(n);
}
}
好了,此处我们将所有相交的点已经加入,但是在Triangulator这个类中。原作者使用的是凸包算法,也就是在空间的游离点中,寻找所有最外围的点,把他们围成新的Mesh。但是如果我们的模型是具有凹字型结构,就无法适用这套算法,所以我们采用的是有向连通图的算法,通过线段和线段,最近点和点进行合并的算法。达成连接一个空间中游离点的最大环
while (testmapped.Count > 1)
{
Mapped2D mpnext = testmapped.Find(m => m.index == currentmp.index);
newmapped.Add(mpnext);
testmapped.Remove(mpnext);
float minDistance = float.MaxValue;
Mapped2D mpnear = testmapped[0];
testmapped.ForEach(m =>
{
float distance = Vector2.Distance(m.mappedValue, mpnext.mappedValue);
if (distance < minDistance)
{
minDistance = distance;
mpnear = m;
}
});
testmapped.Remove(mpnear);
currentmp = mpnear;
}
这些点就自然而然的连起来了,再用上平面三角面的构造函数,构造出来侧面的Mesh,这样就大功告成了!
这是结果
以后我还会分享一些在工作中遇到的困难和解决思路~希望各位大佬海涵