Files
MinFt/Client/Assets/Scripts/Tools/Triangulator.cs
2026-04-27 12:07:32 +08:00

120 lines
3.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
using System.Collections.Generic;
public class Triangulator
{
private List<Vector2> m_points = new List<Vector2>();
public Triangulator(Vector2[] points)
{
m_points = new List<Vector2>(points);
}
public int[] Triangulate()
{
List<int> indices = new List<int>();
int n = m_points.Count;
if (n < 3)
return indices.ToArray();
int[] V = new int[n];
if (Area() > 0)//如果逆时针选点点的index正向记录
{
for (int v = 0; v < n; v++)
V[v] = v;
}
else
{//如果顺时针选点点的index反向记录
for (int v = 0; v < n; v++)
V[v] = (n - 1) - v;
}
int nv = n;
int count = 2 * nv;
for (int v = nv - 1; nv > 2;)
{
if ((count--) <= 0)
return indices.ToArray();
int u = v;
if (nv <= u)
u = 0;
v = u + 1;
if (nv <= v)
v = 0;
int w = v + 1;
if (nv <= w)
w = 0;
if (Snip(u, v, w, nv, V))//u,v,w三点是否能构成三角面
{
int a, b, c, s, t;
a = V[u];
b = V[v];
c = V[w];
indices.Add(a);
indices.Add(b);
indices.Add(c);
for (s = v, t = v + 1; t < nv; s++, t++)//增加一个三角数据,把这个三角剪去
V[s] = V[t];
nv--;
count = 2 * nv;
}
}
indices.Reverse();//翻转法线
return indices.ToArray();
}
private float Area()
{
int n = m_points.Count;
float A = 0.0f;
for (int p = n - 1, q = 0; q < n; p = q++)
{
Vector2 pval = m_points[p];
Vector2 qval = m_points[q];
A += pval.x * qval.y - qval.x * pval.y;//两向量叉乘只取z值如果为负则顺时针
}
return (A * 0.5f);
}
private bool Snip(int u, int v, int w, int n, int[] V)
{
int p;
Vector2 A = m_points[V[u]];
Vector2 B = m_points[V[v]];
Vector2 C = m_points[V[w]];
if (Mathf.Epsilon > (((B.x - A.x) * (C.y - A.y)) - ((B.y - A.y) * (C.x - A.x))))//判断三点是否为顺时针排列,如果是的话是凹陷,不计算三角
return false;
for (p = 0; p < n; p++)
{
if ((p == u) || (p == v) || (p == w))
continue;
Vector2 P = m_points[V[p]];
if (InsideTriangle(A, B, C, P))//是否有其他的点在三角形内部,是,不计算三角
return false;
}
return true;
}
private bool InsideTriangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P)
{
float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
float cCROSSap, bCROSScp, aCROSSbp;
ax = C.x - B.x; ay = C.y - B.y;
bx = A.x - C.x; by = A.y - C.y;
cx = B.x - A.x; cy = B.y - A.y;
apx = P.x - A.x; apy = P.y - A.y;
bpx = P.x - B.x; bpy = P.y - B.y;
cpx = P.x - C.x; cpy = P.y - C.y;
aCROSSbp = ax * bpy - ay * bpx;
cCROSSap = cx * apy - cy * apx;
bCROSScp = bx * cpy - by * cpx;
return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));//都是逆时针P在ABC内
}
}