Unity 三角剖分多边形三角化
一、常用三角化的方法
在某些时候需要对多边形构建mesh,需要对多边形进行三角划分,多边形的三角化是将一个多边形分割成若干个不重叠的三角形的过程。以下是几种常见的三角化方法:
1. 耳切法(Ear Clipping Method):
这是最经典和简单的一种方法。其基本思想是不断找到并移除多边形中的“耳朵”(即包含两个相邻顶点和一个对角线构成的三角形)。
每次找到一个耳朵,将其作为一个三角形加入结果中,然后移除这个顶点,继续寻找下一个耳朵,直到多边形被完全分解为三角形。
时间复杂度为 O(n²),其中 n 是多边形的顶点数。
2. Delaunay三角化(Delaunay Triangulation):
Delaunay三角化是生成三角网格的一种方法,保证所有三角形的内角尽可能大(避免瘦长三角形)。
它通常用于点集的三角化,但也可以扩展用于简单多边形。
有多种实现算法,例如增量法、逐步插入法、分治法等,时间复杂度一般为 O(nlogn)。
3. 分治法(Divide and Conquer Method):
这种方法类似于快速排序的思想,将多边形分成更小的部分,然后递归地对每一部分进行三角化,最后合并结果。
适用于复杂多边形,时间复杂度为 O(nlogn)。
4. 扫描线法(Sweep Line Algorithm):
这种方法通过一条“扫描线”从一侧扫描到另一侧,将多边形分割成若干个“耳朵”。它适用于简单多边形,但实现起来较为复杂。
时间复杂度为 O(nlogn)。
5. Greene's Algorithm:
这种方法是基于三角化和修正的组合算法。它首先对多边形进行初步三角化,然后修正这些三角形以满足条件。
适用于简单和复杂多边形,时间复杂度为 O(nlogn)。
6. Seidel's Algorithm:
Seidel's算法是一种快速三角化算法,它通过使用平衡树和分割线快速地对多边形进行三角化。
二、Unity中进行三角划分的方法
在Unity中实现三角化,官方没有可以直接调用的方法,但是可以取个巧,使用PolygonCollider2D类的CreateMesh方法来创建mesh,
具体的实现可以参考我的另一篇文章:https://www.cnblogs.com/Jason-c/p/17579191.html
PolygonCollider2D创建mesh对于简单的多边形处理的效果还是很好的,但是对于有自相交的多边形,相交的部分是个洞,这就很难受。
偶然间发现前端在使用Three.js绘制多边形时,效果挺好,扒了Three.js的源码,转译成了C#,主要转译的是Three.js的ShapeUtils.js和Earcut.js
想要完整的unity工程的小伙伴,点击这里查看完整Unity工程源码,里面附带示例。
写个代码看下效果:
using System.Collections; using System.Collections.Generic; using Triangularization; using UnityEngine; public class Test : MonoBehaviour { public PolygonCollider2D polygonCollider; public MeshFilter unity; public MeshFilter three; void Start() { Vector3[] verts = new Vector3[polygonCollider.points.Length]; for (int i = 0; i < polygonCollider.points.Length; i++) { verts[i] = polygonCollider.points[i]; } unity.mesh = polygonCollider.CreateMesh(false,false); unity.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Unlit/Texture")); if (ShapeUtils.Triangulate(new List<Vector3>(verts),null,out int[] t,out Vector3[] v)) { three.mesh.vertices = v; three.mesh.triangles = t; } three.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Unlit/Texture")); } }
Three.js在创建多边形mesh时的流程相对比较复杂,需要创建Shape,ShapeGeometry等,这里在转译Three.js时,简化了调用逻辑,
直接调用ShapeUtils类的public static bool Triangulate(List<Vector3> shapeVertices, List<List<Vector3>> shapeHoles, out int[] triangles, out Vector3[] vertices)就可以,其中:
shapeVertices参数表示多边形的轮廓点,需要是有序的,是顺时针还是逆时针无所谓,会自动检查然后转成顺时针,注意:Vector3只会使用x,y的值,z值会被忽略
shapeHoles参数表示多边形内洞的轮廓,也是需要有序的,注意:Vector3只会使用x,y的值,z值会被忽略
triangles参数表示返回的三角形索引
vertices参数表示顶点数据,是顶点数据和三角形索引是对应的
最后做了数据的检查,数据OK时才会返回true
博客园Jason_c微信打赏码
如果本篇文档对你有帮助,打赏Jason_c根华子吧,他的私房钱被老婆没收了,呜呜!