您的位置:首页 > 移动开发 > Unity3D

unity实现任意多边形三角剖分

2017-08-12 13:39 1551 查看
项目有一个对任意形状截面生成3维物体的需求,需要用到三角化的算法。如果截面是凸多边形,那么非常简单,以任意一点为起点按顺序切分即可:



/// <summary>
/// 局限性三角剖分
/// </summary>
/// <returns></returns>
public static int[] LimitedTriangleIndex(Vector3[] verts)
{
int len = verts.Length;
//若是闭环去除最后一点
if (len > 1 && MathUtil.IsEqual(verts[0], verts[len - 1]))
{
len--;
}
int triangleNum = len - 2;
int[] triangles = new int[triangleNum * 3];
for (int i = 0; i < triangleNum; i++)
{
int start = i * 3;
triangles[start] = 0;
triangles[start + 1] = i + 1;
triangles[start + 2] = i + 2;
}
return triangles;
}


而对于凹多边形这种方法就无能为力了:



网上可以找到很多论文,我参考了其中一篇(主要是作者写的接地气,简单易懂),实现了需求。

论文地址:三维模型重建中的凹多边形三角剖分

c#代码:

/// <summary>
/// 三角剖分
/// 1.寻找一个可划分顶点
/// 2.分割出新的多边形和三角形
/// 3.新多边形若为凸多边形,结束;否则继续剖分
///
/// 寻找可划分顶点
/// 1.顶点是否为凸顶点:顶点在剩余顶点组成的图形外
/// 2.新的多边形没有顶点在分割的三角形内
/// </summary>
private static List<int> WidelyTriangleIndex(List<Vector2> verts, List<int> indexes)
{
int len = verts.Count;
if (len <= 3) return ConvexTriangleIndex(indexes);

int searchIndex = 0;
List<int> covexIndex = new List<int>();
bool isCovexPolygon = true;

for (searchIndex = 0; searchIndex < len; searchIndex++)
{
List<Vector2> polygon = new List<Vector2>(verts.ToArray());
polygon.RemoveAt(searchIndex);
if (IsPointInsidePolygon(verts[searchIndex], polygon))
{
isCovexPolygon = false;
break;
}
else
{
covexIndex.Add(searchIndex);
}
}

if (isCovexPolygon) return ConvexTriangleIndex(indexes);

int canFragementIndex = -1;
for (int i = 0; i < len; i++)
{
if (i > searchIndex)
{
List<Vector2> polygon = new List<Vector2>(verts.ToArray());
polygon.RemoveAt(i);
if (!IsPointInsidePolygon(verts[i], polygon) && IsFragementIndex(i, verts))
{
canFragementIndex = i;
break;
}
}
else
{
if (covexIndex.IndexOf(i) != -1 && IsFragementIndex(i, verts))
{
canFragementIndex = i;
break;
}
}
}

if (canFragementIndex < 0)
{
Debug.LogError("数据有误找不到可划分顶点");
return new List<int>();
}

List<int> tTriangles = new List<int>();
int next = (canFragementIndex == len - 1) ? 0 : canFragementIndex + 1;
int prev = (canFragementIndex == 0) ? len - 1 : canFragementIndex - 1;
tTriangles.Add(indexes[prev]);
tTriangles.Add(indexes[canFragementIndex]);
tTriangles.Add(indexes[next]);
verts.RemoveAt(canFragementIndex);
indexes.RemoveAt(canFragementIndex);

List<int> leaveTriangles = WidelyTriangleIndex(verts, indexes);
return tTriangles.Concat(leaveTriangles).ToList();
}

/// <summary>
/// 是否是可划分顶点:新的多边形没有顶点在分割的三角形内
/// </summary>
private static bool IsFragementIndex(int index, List<Vector2> verts)
{
int len = verts.Count;
List<Vector2> triangleVert = new List<Vector2>();
int next = (index == len - 1) ? 0 : index + 1;
int prev = (index == 0) ? len - 1 : index - 1;
triangleVert.Add(verts[prev]);
triangleVert.Add(verts[index]);
triangleVert.Add(verts[next]);
for (int i = 0; i < len; i++)
{
if (i != index && i != prev && i != next)
{
if (IsPointInsidePolygon(verts[i], triangleVert))
{
return false;
}
}
}
return true;
}
/// <summary>
/// 点与多边形的位置关系
/// </summary>
/// <param name="point"></param>
/// <param name="polygonVerts">多边形顶点按顺序排列</param>
/// <returns></returns>
public static bool IsPointInsidePolygon(Vector2 point, Vector2[] polygonVerts)
{
int len = polygonVerts.Length;
Ray2D ray = new Ray2D(point, new Vector2(0, 1)); //测试射线
int interNum = 0;

for (int i = 1; i < len; i++)
{
if (IsDetectIntersect(ray, polygonVerts[i - 1], polygonVerts[i]))
{
interNum++;
}
}
if (!MathUtil.IsEqual(polygonVerts[0], polygonVerts[len - 1]))
{
if (IsDetectIntersect(ray, polygonVerts[len - 1], polygonVerts[0]))
{
interNum++;
}
}
int remainder = interNum % 2;
return remainder == 1;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: