基本原理
- 逐点顶处理多边形,计算出每个顶点的相邻向量
- 舍弃相邻向量共线的顶点(将多边形简化,减少三角网格数量)
- 由顶点相邻向量与外扩距离计算出外扩后的新顶点坐标
- 由新点顶坐标顺序生成三角形数组,根据新点顶坐标和三角形数组绘制新多边形
细节
多边形三角网格简化:
凹点与凸点:
关键步骤
如何计算出外扩后新顶点坐标?
已知点Q为原顶点,现在要求外扩后点P的坐标(外扩距离为D)
1.P = Q + 向量QP
2.由平行四边形法则可知向量QP = 向量QN + 向量QM
3.D = |向量QM| * sinA
4.sinA可由点Q相邻两边向量QA与QB叉乘得到
归纳总结出计算步骤:
1.计算顶点邻边向量(注意向量方向,外扩与收缩向量方向相反)
2.利用邻边向量(单位化)叉乘得到SinA值
3.判断顶点是凹点还是凸点(邻边向量叉乘得到的法向量与点顶法线同向为凸点否则为凹点)
4.如果SinA值为0,则表示邻边向量共线,可以舍弃该顶点(对多边形顶点做简化操作)
5.凸点:Q = P + d/sinA (Normalize(QN) + Normalize(QM))
凹点:Q = P - d/sinA (Normalize(QN) + Normalize(QM))
核心代码:
//缩放系数
public float thickness = 0.5f;
//目标多边形
public DrawPolygon TargetPolygon;
//新生成多边形
private DrawPolygon NewPolygon;
//相邻向量集合
private List<AdjacentVector> list;
//新多边形点顶集合
private List<Vector3> vectorList;
//绘制外扩后的多边形
public void DrawNewPolygon()
{
list.Clear();
vectorList.Clear();
//获取目标多边形的网格数据
MeshFilter meshFilter = TargetPolygon.GetComponent<MeshFilter>();
Mesh mesh = null;
if (Application.isPlaying)
mesh = meshFilter.mesh;
else
mesh = meshFilter.sharedMesh;
//点顶数据
Vector3[] vertices = mesh.vertices;
Vector3[] normal = mesh.normals;
//所有点顶做差求相邻向量集合
for(int i=0;i<vertices.Length;i++)
{
//计算相邻点顶向量
Vector3 v1 = vertices[i] - vertices[i == vertices.Length - 1 ? 0 : i + 1];
Vector3 v2 = vertices[i] - vertices[i == 0 ? vertices.Length - 1 : i - 1];
//判断是否为凹点(相邻向量的法向量与点顶法向量是否相反)
bool Cancave = Vector3.Dot(Vector3.Cross(v1, v2), normal[i]) < 0;
//加入向量集合
list.Add(new AdjacentVector(v1, v2, Cancave));
}
//计算新点顶位置
for(int i=0;i<vertices.Length;i++)
{
Vector3 v1 = list[i].v1;
Vector3 v2 = list[i].v2;
//判断相邻向量是否共线 如果共线则不需要处理
float sin = Vector3.Cross(v1, v2).magnitude;
if(sin>0)
{
//凹点反向
sin = list[i].isConcave ? -sin : sin;
//新点顶计算公式:Q = P + (v1+v2);
Vector3 point = vertices[i] + thickness / sin * (v1 + v2);
//加入新多边形点顶集合
vectorList.Add(point);
}
}
//绘制新多边形
NewPolygon.Vertices = vectorList.ToArray();
NewPolygon.Draw();
}
得到新多边形点顶后如何生成三角形网格:
基本思路:选取多边形某个点顶,将该顶点与除相邻顶点外的其他顶点进行连线,将多边形分解成n-2个(n为顶点数)三角形
选取A点,连线AC与AD
三角形数组:ABC ACD ADE(注意保持所有三角形的点顶顺序是同序,顺时针与逆时针显示的正反面不同)
当遇到特殊的多边形时随机选取顶点进行三角化会出现问题:
解决方法:当选取某顶点进行三角化时,若按顺序遍历顶点得到的三角形时针顺序不一致则会得到错误的三角化结果,需要选取另一顶点进行三角化。
图中错误情况时:边AB与AC构成三角形ABC是逆时针,边AC与AD构成三角形ACD是顺时针,所以得到了错误的三角化结果
核心代码:
/// <summary>
/// 根据点顶顺序将多边形转化为三角形数组
/// </summary>
/// <param name="vertex">顶点数组</param>
/// <returns></returns>
public int[] Trianglate(Vector3[] vertex)
{
if (vertex.Length < 3)
return null;
List<int> list = new List<int>();
int i = 0;
int j = i + 1;
int k = i + 2;
//基准向量(本例选取逆时针的法向量)
Vector3 stander = new Vector3(0, 0, 1);
while (true)
{
Vector3 tem1 = vertex[j] - vertex[i];
Vector3 tem2 = vertex[k] - vertex[i];
//判断是否保持逆时针
float tem = Vector3.Dot(Vector3.Cross(tem1, tem2), stander);
if(tem>0)
{
//保持逆时针则将三角形顶点按顺序加入集合中
list.Add(i);
list.Add(j);
list.Add(k);
j = (++j) % vertex.Length;
k = (++k) % vertex.Length;
if (k == i)
break;
}
else
{
//若不保持逆时针则选取下一个顶点进行循环
i++;
j = i + 1;
k = i + 2;
list.Clear();
continue;
}
}
return list.ToArray();
}
效果
版权声明:本文为qq_41655524原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。