unity之不规则多边形uv贴图

mesh的uv贴图想必大家都知道是三角形组成原理,我使用三角剖分的方法去解决不规则多边形的uv贴图,

三角剖分算法大家可以百度上去看,很多种教程,具体脚本算法如下:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class TriangleSubdivision  :MonoBehaviour{
	public static int[] TriangulatePolygon (Vector2[] XZofVertices) {
		int VertexCount = XZofVertices.Length;
        float xmin = XZofVertices[0].x;
        float ymin = XZofVertices[0].y;
        float xmax = xmin;
        float ymax = ymin;
        for (int ii1 = 1; ii1 < VertexCount; ii1++)
        {
			if (XZofVertices[ii1].x < xmin) 
			{ 
				xmin = XZofVertices[ii1].x; 
			}
			else if (XZofVertices[ii1].x > xmax) 
			{
				xmax = XZofVertices[ii1].x; 
			}
			if (XZofVertices[ii1].y < ymin) 
			{ 
				ymin = XZofVertices[ii1].y; 
			}
			else if (XZofVertices[ii1].y > ymax) 
			{ 
				ymax = XZofVertices[ii1].y;
			}
        }
        float dx = xmax - xmin;
        float dy = ymax - ymin;
        float dmax = (dx > dy) ? dx : dy;
        float xmid = (xmax + xmin) * 0.5f;
        float ymid = (ymax + ymin) * 0.5f;
        Vector2[] ExpandedXZ = new Vector2[3 + VertexCount];
        for (int ii1 = 0; ii1 < VertexCount; ii1++)
        {
			ExpandedXZ[ii1] = XZofVertices[ii1];
        }
		//外接三角形的三个点
		ExpandedXZ[VertexCount] = new Vector2((xmid - 2 * dmax), (ymid - dmax));
        ExpandedXZ[VertexCount + 1] = new Vector2(xmid, (ymid + 2 * dmax));
        ExpandedXZ[VertexCount + 2] = new Vector2((xmid + 2 * dmax), (ymid - dmax));
		List<Triangle> TriangleList = new List<Triangle>();
        TriangleList.Add(new Triangle(VertexCount, VertexCount+1, VertexCount+2));
        for (int ii1 = 0; ii1 < VertexCount; ii1++)
        {
			List<Edge> Edges = new List<Edge>();
			for (int ii2 = 0; ii2 < TriangleList.Count; ii2++)
			{
				if (TriangulatePolygonSubFunc_InCircle(ExpandedXZ[ii1], ExpandedXZ[TriangleList[ii2].p1],ExpandedXZ[TriangleList[ii2].p2],ExpandedXZ[TriangleList[ii2].p3]))
				{
					Edges.Add(new Edge(TriangleList[ii2].p1, TriangleList[ii2].p2));
		            Edges.Add(new Edge(TriangleList[ii2].p2, TriangleList[ii2].p3));
		            Edges.Add(new Edge(TriangleList[ii2].p3, TriangleList[ii2].p1));
		            TriangleList.RemoveAt(ii2);
		            ii2--;
				}
			}
			if (ii1 >= VertexCount) { continue; }
			for (int ii2 = Edges.Count - 2; ii2 >= 0; ii2--)
			{
				for (int ii3 = Edges.Count - 1; ii3 >= ii2 + 1; ii3--)
				{
					if (Edges[ii2].Equals(Edges[ii3]))
					{
						Edges.RemoveAt(ii3);
						Edges.RemoveAt(ii2);
                        ii3--;
                        continue;
					}
				}
			}
			for (int ii2 = 0; ii2 < Edges.Count; ii2++)
            {
				TriangleList.Add(new Triangle(Edges[ii2].p1, Edges[ii2].p2, ii1));
			}
            Edges.Clear();
            Edges = null;
		}
		//大于点集外围的点 外接三角形的三个确认点
        for (int ii1 = TriangleList.Count - 1; ii1 >= 0; ii1--)
        {
			if (TriangleList[ii1].p1 >= VertexCount ||TriangleList[ii1].p2 >= VertexCount ||TriangleList[ii1].p3 >= VertexCount)
            { 
				TriangleList.RemoveAt(ii1); 
			}
        }
		//不在点集区域内的面
		for(int ii3 = 0;ii3<TriangleList.Count;ii3++){
			if(TriangleInPolygonOuter(XZofVertices,XZofVertices[TriangleList[ii3].p1],XZofVertices[TriangleList[ii3].p2],XZofVertices[TriangleList[ii3].p3])){
				TriangleList.RemoveAt(ii3);
				ii3--;
			}
		}
        TriangleList.TrimExcess();
        int[] Triangles = new int[3 * TriangleList.Count];
        for (int ii1 = 0; ii1 < TriangleList.Count; ii1++)
        {
			Triangles[3 * ii1] = TriangleList[ii1].p1;
	        Triangles[3 * ii1 + 1] = TriangleList[ii1].p2;
	        Triangles[3 * ii1 + 2] = TriangleList[ii1].p3;
        }
		return Triangles;
	}
        // float.Epsilon这个值为无限接近于0的值,我再pc上正常,在ios端就不能用了,我打印出直接输出0,大家可以模拟一个值,0.0000000001,或者什么   趋近于0,但不等于0就行了,
	static bool TriangulatePolygonSubFunc_InCircle(Vector2 p, Vector2 p1, Vector2 p2, Vector2 p3) {
		if (Mathf.Abs(p1.y - p2.y) < float.Epsilon &&Mathf.Abs(p2.y - p3.y) < float.Epsilon)
        { 
			return false; 
		}
        float m1, m2, mx1, mx2, my1, my2, xc, yc;
        if (Mathf.Abs(p2.y - p1.y) < float.Epsilon)
        {
			m2 = -(p3.x - p2.x) / (p3.y - p2.y);
            mx2 = (p2.x + p3.x) * 0.5f;
            my2 = (p2.y + p3.y) * 0.5f;
            xc = (p2.x + p1.x) * 0.5f;
            yc = m2 * (xc - mx2) + my2;
        }
        else if (Mathf.Abs(p3.y - p2.y) < float.Epsilon)
        {
            m1 = -(p2.x - p1.x) / (p2.y - p1.y);
            mx1 = (p1.x + p2.x) * 0.5f;
            my1 = (p1.y + p2.y) * 0.5f;
            xc = (p3.x + p2.x) * 0.5f;
            yc = m1 * (xc - mx1) + my1;
        }
        else
        {
            m1 = -(p2.x - p1.x) / (p2.y - p1.y);
            m2 = -(p3.x - p2.x) / (p3.y - p2.y);
            mx1 = (p1.x + p2.x) * 0.5f;
            mx2 = (p2.x + p3.x) * 0.5f;
            my1 = (p1.y + p2.y) * 0.5f;
            my2 = (p2.y + p3.y) * 0.5f;
            xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
            yc = m1 * (xc - mx1) + my1;
        }
		float dx = p2.x - xc;
        float dy = p2.y - yc;
        float rsqr = dx * dx + dy * dy;
        dx = p.x - xc;
        dy = p.y - yc;
        double drsqr = dx * dx + dy * dy;
        return (drsqr <= rsqr);
    }
	static bool TriangleInPolygonOuter(Vector2[] pList,Vector2 p1,Vector2 p2,Vector2 p3){
		Vector2 centrePoint = new Vector2((p1.x+p2.x+p3.x)/3,(p1.y+p2.y+p3.y)/3);
		int crossNum = 0;
        for (int i = 0; i < pList.Length; i++)
        {
			if (IsPointInLine(centrePoint.x, centrePoint.y, pList[i].x, pList[i].y, pList[(i+1)%pList.Length].x, pList[(i+1)%pList.Length].y)==0)
            {
                crossNum=crossNum+1;
				continue;
            }else if(IsPointInLine(centrePoint.x, centrePoint.y, pList[i].x, pList[i].y, pList[(i+1)%pList.Length].x, pList[(i+1)%pList.Length].y)==2){
				crossNum = 1;
				break;
			}
        }
		if ((crossNum % 2) == 0)
		{
			return true;
        }
		crossNum = 0;
//		}
        return false;
	}
	//0   在外  1  在内   2  边上
	static int IsPointInLine(float x,float y,float x1,float y1,float x2,float y2)
    {
		float maxY =y1;
        float minY = y2;
		if(y1>y2){
		    maxY = y1;
			minY = y2;
		}else{
			maxY = y2;
			minY = y1;
		}
		float averageX = (x1+x2)/2;
		float averageY = (y1+y2)/2;
		if(y==averageY&&x==averageX){
			return 2;
		}
        if (y < maxY && y >minY)
        {
            if (x >(x1 + (x2 - x1) * (y - y1) / (y2 - y1)))
            {
                return 0;
            }
        }
        return 1;
    }
}
 struct Triangle
{
	public int p1;
    public int p2;
    public int p3;
    public Triangle(int point1, int point2, int point3)
    {
		p1 = point1; p2 = point2; p3 = point3;
    }
}
class Edge
{
	public int p1;
	public int p2;
	public Edge(int point1, int point2)
    {
		p1 = point1; p2 = point2;
    }
	public Edge() : this(0, 0)
    {}
	public bool Equals(Edge other)
    {
		return ((this.p1 == other.p2) && (this.p2 == other.p1)) ||((this.p1 == other.p1) && (this.p2 == other.p2));
    }
}

使用也很方便,直接调用 TriangulatePolygon,传入你所设置点的坐标数组,它是二维的,返回的就是坐标数组对应的数组下标编号(mesh.triangles)数组,

三角剖分是利用图形外切圆,判断不在多边形内的三角面,使用引射线法,当然大家也可以使用其他的,在这里我使用的这种,具体朋友们可以自己模拟几个点去测试,

下一章我打算写弧形uv贴图,和弧形面贴图,先给出下一章的图形效果,不懂的大家可以随时讨论,由于自己写作水平有限,所以解释的不太清楚,大家可以随时找我讨论,

共同学习进步,相信你们了解了那几个算法后,这一看就明白了,可能也有我没考虑到的,欢迎大家踊跃提出你们的意见



  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值