Unity 自定义多边形创建
多边形的创建
Unity中使用Mesh类创建多边形,一般是将多边形划分为三角形后逐一拼接构成。
凸多边形的划分较为简单:
在多边形的任意一边上任取一点P,连接P点与其不相邻的其它各顶点的线段,可以把多边形边形分成N个三角形。
凹多边形划分时上述方法不再适用,因此可以使用耳切法进行划分,耳切法较为详细的讲述:
1.原篇:
Triangulation by Ear Clipping (geometrictools.com)
2.翻译:Triangulation by Ear Clipping(耳切法处理多边形三角划分) - 行走_ - 博客园 (cnblogs.com)
耳切法划分多边形为三角形
ref:(21条消息) 判断多边形的顺逆性_Leopard-C的博客-CSDN博客
ref:(21条消息) 使用耳切法将多边形三角化_贪玩的孩纸时代的博客-CSDN博客
using System;
using System.Collections.Generic;
using UnityEngine;namespace PolygonTool
{/// /// 判断凹点,凸点,耳朵的比较轴/// public enum CompareAxle{X,YT,YF,Z}/// /// 对多边形处理/// public class Triangulation{/// /// 判断凹凸的时候的比对轴/// private CompareAxle _compareAxle = CompareAxle.YT;/// /// 多边形顶点/// private List _polygonVertexs = new List();/// /// 顶点序列/// private List _vertexsSequence = new List();/// /// 节点管理器/// private NodeManager _nodeManager = new NodeManager();/// /// 初始化/// /// 多边形顶点public Triangulation(List polygonVertexs){this._polygonVertexs = polygonVertexs;_nodeManager.Init(polygonVertexs);}/// /// 设置比较轴/// /// public void SetCompareAxle(CompareAxle compareAxle){this._compareAxle = compareAxle;}/// /// 设置比较轴/// /// public void SetCompareAxle(bool clockwise){if (clockwise){this._compareAxle = CompareAxle.YT;}else{this._compareAxle = CompareAxle.YF;}}/// /// 获取三角形的顶点序列/// public int[] GetTriangles(){while (_nodeManager.LinkedListLength >= 3){SplitResult sr = SplitPolygon();//if (sr == null){Debug.Log("null");return null;}}return _vertexsSequence.ToArray();}/// /// 计算凹顶点,凸顶点,耳朵/// private SplitResult SplitPolygon(){//凹点List _concaveVertexs = new List();//凸点List _raisedVertexs = new List();//耳朵List _polygonEars = new List();//起始节点Node currentNode = _nodeManager.FirstNode;#region 计算凹顶点,凸顶点for (int i = 0; i < _nodeManager.LinkedListLength; i++){Vector3 one = currentNode.vertex - currentNode.lastNode.vertex;Vector3 two = currentNode.nextNode.vertex - currentNode.vertex;Vector3 crossRes = Vector3.Cross(one, two);if (_compareAxle == CompareAxle.YT){if (crossRes.y < 0){_concaveVertexs.Add(currentNode);}else{_raisedVertexs.Add(currentNode);}}if (_compareAxle == CompareAxle.YF){if (crossRes.y > 0){_concaveVertexs.Add(currentNode);}else{_raisedVertexs.Add(currentNode);}}if (_compareAxle == CompareAxle.X){if (crossRes.x > 0){_concaveVertexs.Add(currentNode);}else{_raisedVertexs.Add(currentNode);}}if (_compareAxle == CompareAxle.Z){if (crossRes.z > 0){_concaveVertexs.Add(currentNode);}else{_raisedVertexs.Add(currentNode);}}_polygonEars.Add(currentNode);currentNode = currentNode.nextNode;}for (int i = 0; i < _concaveVertexs.Count; i++){_polygonEars.Remove(_concaveVertexs[i]);}#endregion#region 计算耳朵List needRemoveIdList = new List();for (int i = 0; i < _polygonEars.Count; i++){Node earNode = _polygonEars[i];Node compareNode = earNode.nextNode.nextNode;while (compareNode != earNode.lastNode){bool isIn = IsIn(compareNode.vertex, earNode.lastNode.vertex, earNode.vertex,earNode.nextNode.vertex);if (isIn == true){if (_polygonEars.Contains(_polygonEars[i])){needRemoveIdList.Add(_polygonEars[i].id);}break;}compareNode = compareNode.nextNode;}}for (int j = 0; j < needRemoveIdList.Count; j++){for (int i = 0; i < _polygonEars.Count; i++){if (_polygonEars[i].id == needRemoveIdList[j]){_polygonEars.RemoveAt(i);}}}#endregion#region 打印初始化结果//Debug.Log("凸点");//for (int i = 0; i < _raisedVertexs.Count; i++)//{// Debug.Log(_raisedVertexs[i].id);//}//Debug.Log("凹点");//for (int i = 0; i < _concaveVertexs.Count; i++)//{// Debug.Log(_concaveVertexs[i].id);//}//Debug.Log("耳朵");//for (int i = 0; i < _polygonEars.Count; i++)//{// Debug.Log(_polygonEars[i].id);//}//Debug.Log("-----------------------------------------------");#endregion//耳朵为空说明不是简单多边形 多边形三角化失败if (_polygonEars.Count == 0){return null;}_vertexsSequence.Add(_polygonEars[0].lastNode.id);_vertexsSequence.Add(_polygonEars[0].id);_vertexsSequence.Add(_polygonEars[0].nextNode.id);_nodeManager.RemoveNode(_polygonEars[0]);return new SplitResult(_raisedVertexs, _concaveVertexs, _polygonEars);}/// /// 判断一点是否在三角形内/// /// 一点/// /// /// /// public bool IsIn(Vector3 p, Vector3 a, Vector3 b, Vector3 c){Vector3 pa = p - a;Vector3 pb = p - b;Vector3 pc = p - c;Vector3 t1 = Vector3.Cross(pa, pb);Vector3 t2 = Vector3.Cross(pb, pc);Vector3 t3 = Vector3.Cross(pc, pa);bool isIn2 = t1.y >= 0 && t2.y >= 0 && t3.y >= 0 || t1.y <= 0 && t2.y <= 0 && t3.y <= 0;return isIn2;}public bool IsClockwise_1(List points){List pts = new List();for (int i = 0; i < points.Count; i++){MYPOINT m = new MYPOINT(points[i].x, points[i].z);pts.Add(m);}double d = 0;int size = pts.Count;for (int i = 0; i < size - 1; i++){d += -0.5 * (pts[i + 1].y + pts[i].y) * (pts[i + 1].x - pts[i].x);}// 注意,这个容易忽略!最后一个点与第一个点构成的边d += -0.5 * (pts[0].y + pts[size - 1].y) * (pts[0].x - pts[size - 1].x);if (d < 0)return true;elsereturn false;}/// /// 管理多边形 构成一个双向链表/// public class NodeManager{private List _nodeList = new List();public int LinkedListLength{get { return _nodeList.Count; }}public Node FirstNode{get { return _nodeList[0]; }}public void Init(List vertexs){for (int i = 0; i < vertexs.Count; i++){Node node = new Node(i, vertexs[i]);_nodeList.Add(node);}for (int i = 0; i < LinkedListLength; i++){if (i == 0){_nodeList[i].lastNode = _nodeList[LinkedListLength - 1];_nodeList[i].nextNode = _nodeList[1];}else if (i == LinkedListLength - 1){_nodeList[i].lastNode = _nodeList[LinkedListLength - 2];_nodeList[i].nextNode = _nodeList[0];}else{_nodeList[i].lastNode = _nodeList[i - 1];_nodeList[i].nextNode = _nodeList[i + 1];}}}public void RemoveNode(Node node){_nodeList.Remove(node);node.lastNode.nextNode = node.nextNode;node.nextNode.lastNode = node.lastNode;}}public class Node{public int id;public Vector3 vertex;public Node lastNode;public Node nextNode;public Node(int id, Vector3 vertex){this.id = id;this.vertex = vertex;}public Node(int id, Vector3 vertex, Node lastNode, Node nextNode){this.id = id;this.vertex = vertex;this.lastNode = lastNode;this.nextNode = nextNode;}}public class SplitResult{/// /// 凸顶点/// public List raisedVertexs;/// /// 凹顶点/// public List concaveVertexs;/// /// 耳朵/// public List polygonEars;public SplitResult(List raisedVertexs, List concaveVertexs, List polygonEars){this.raisedVertexs = raisedVertexs;this.concaveVertexs = concaveVertexs; this.polygonEars = polygonEars;}}//自定义MyPoint类 多边形顶点顺逆时针方向判断public class MYPOINT{public double x;public double y;public MYPOINT(double xx, double yy){x = xx;y = yy;}}}
}
多边形创建(立方体)
points为多边形的顶点集合链表
vert为多边形顶点位置链表
indices为多边形顶点绘制序号链表
private GameObject CreateMesh(){#region 底面添加Triangulation triangulation = new Triangulation(points);bool clockwise = triangulation.IsClockwise_1(points);triangulation.SetCompareAxle(clockwise);int[] trisIndex_Bottom = triangulation.GetTriangles();for (int i = 0; i < trisIndex_Bottom.Length; i++){verts.Add(points[trisIndex_Bottom[i]]);}for (int i = 0; i < trisIndex_Bottom.Length; i += 3){if (clockwise){indices.Add(i);indices.Add(i + 2);indices.Add(i + 1);}else{indices.Add(i + 1);indices.Add(i + 2);indices.Add(i);}}#endregion#region 顶面添加for (int i = 0; i < points.Count; i++){points_top.Add(points[i] + new Vector3(0, 1, 0));}Triangulation triangulation_top = new Triangulation(points_top);triangulation_top.SetCompareAxle(clockwise);int[] trisIndex_Top = triangulation_top.GetTriangles();for (int i = 0; i < trisIndex_Top.Length; i++){verts.Add(points_top[trisIndex_Top[i]]);}for (int i = 0; i < trisIndex_Top.Length; i += 3){if (clockwise){indices.Add(i + trisIndex_Bottom.Length + 1);indices.Add(i + trisIndex_Bottom.Length + 2);indices.Add(i + trisIndex_Bottom.Length);}else{indices.Add(i + trisIndex_Bottom.Length);indices.Add(i + trisIndex_Bottom.Length + 2);indices.Add(i + trisIndex_Bottom.Length + 1);}}#endregion#region 侧面添加for (int i = 0; i < points.Count; i++){verts.Add(points[i]);verts.Add(points[i + 1 == points.Count ? 0 : i + 1]);verts.Add(points_top[i]);verts.Add(points_top[i + 1 == points.Count ? 0 : i + 1]);}for (int i = 0; i < points.Count; i++){indices.Add(clockwise? trisIndex_Bottom.Length * 2 + (i * 4) + 1: trisIndex_Bottom.Length * 2 + (i * 4));indices.Add(trisIndex_Bottom.Length * 2 + (i * 4) + 3);indices.Add(clockwise ? trisIndex_Bottom.Length * 2 + (i * 4): trisIndex_Bottom.Length * 2 + (i * 4) + 1);indices.Add(clockwise ? trisIndex_Bottom.Length * 2 + (i * 4) + 3: trisIndex_Bottom.Length * 2 + (i * 4));indices.Add(trisIndex_Bottom.Length * 2 + (i * 4) + 2);indices.Add(clockwise ? trisIndex_Bottom.Length * 2 + (i * 4): trisIndex_Bottom.Length * 2 + (i * 4) + 3);}#endregion#region 网格数据整理Mesh mesh = new Mesh();mesh.SetVertices(verts);mesh.SetIndices(indices, MeshTopology.Triangles, 0);mesh.RecalculateNormals();mesh.RecalculateBounds();#endregion#region 对象创建GameObject meshObj = new GameObject("mesh");MeshFilter filter = meshObj.AddComponent();MeshRenderer renderer = meshObj.AddComponent();renderer.material = material;filter.mesh = mesh;return meshObj;#endregion }
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

