首页 > 代码库 > unity之圆角头像实现

unity之圆角头像实现

重写了一个image组件,将精灵拖进去可调整圆角的大小和平滑度,我写的这个只支持正方形图片,矩形会比较麻烦,暂时还没想到方法

实现思路:

1.如下图,image画图原理就是在一个方框中画三角形,然后形成图片,红线代表方框的坐标系,蓝色代表图片的坐标系,也就是你在这个方框的某个位置上画图片的哪个部位,例如蓝色的(0,0)点,假如image宽度,高度都为2,也就是在黑框的(-1,-1)画一个(0,0)点。

2.如果想要圆角就很简单了,就是在角上多画几个间距相等的点,点越多平滑度越高,例如我图中左上角多加了一个点,四边形也就成了五边形,得到5个点的集合,也就是图中的紫色数字。

3.画图是由很多个三角形构成,(注意添加三角形时,点的方向必须是顺时针的,例如(0,1,2),(2,3,4),(4,5,0)都可以),然后就可以用一个for循环,从0点开始添加三角形(i,i+1,i+2)。添加完成后图也就画好了~~~^_^~~~

4.点的位置,用sin和cos(90/(点的个数))*r(如果想画圆形r就是1/2)得到点在蓝色坐标的位置,红色坐标可以根据蓝色坐标得到,他两关系是固定的嘛。根据宽度得就行(ps:蓝色坐标中,图片的长宽都为1,而红色的是根据image实际的width和height)

技术分享

技术分享
  1 using System.Collections.Generic;
  2 using UnityEngine;
  3 using UnityEngine.UI;
  4 using UnityEngine.Sprites;
  5  
  6 [AddComponentMenu("UI/Circle Image")]
  7 public class CircleImage2 : BaseImage {
  8 
  9     // Use this for initialization
 10     void Awake () {
 11         innerVertices = new List<Vector3>();
 12         outterVertices = new List<Vector3>();
 13     }
 14     
 15     // Update is called once per frame
 16     void Update () {
 17        
 18     }
 19 
 20     
 21     [Range(0, 1)]
 22     public float scale = 1f;
 23      
 24     [Range(2, 30)]
 25     public int segements = 2;
 26 
 27     private List<Vector3> innerVertices;
 28     private List<Vector3> outterVertices;
 29 
 30     protected override void OnPopulateMesh(VertexHelper vh)
 31     {
 32         vh.Clear();
 33         Rect pixelAdjustedRect = this.GetPixelAdjustedRect();
 34 
 35         float w = pixelAdjustedRect.width;
 36         for (int i =0; i < segements+1; i++)
 37         {
 38             UIVertex uivertex = new UIVertex();
 39             uivertex.color = color;
 40             if (i ==0)
 41             {
 42                 uivertex.uv0 = new Vector2((scale / 2) * (1 - Mathf.Sin(i * 90 / segements)),(scale / 2) * (1 - Mathf.Cos(i * 90 / segements)));
 43             }
 44             else
 45             {
 46                 uivertex.uv0 = new Vector2((scale / 2) * (1 - Mathf.Sin(Mathf.PI / (180f /(i * 90 / segements)))), (scale / 2) * (1 - Mathf.Cos(Mathf.PI / (180f / (i * 90 / segements)))));
 47             }
 48             uivertex.position = new Vector3(w*uivertex.uv0.x-w/2,w*uivertex.uv0.y-w/2);
 49             
 50             vh.AddVert(uivertex);
 51         }
 52 
 53         for (int i = 0; i < segements + 1; i++)
 54         {
 55             UIVertex uivertex = new UIVertex();
 56             uivertex.color = color;
 57             if (i == 0)
 58             {
 59                 uivertex.uv0 = new Vector2((scale / 2) - (scale / 2) * Mathf.Cos(i * 90 / segements), (1 - scale / 2) + (scale / 2) * Mathf.Sin(i * 90 / segements));
 60             }
 61             else
 62             {
 63                 uivertex.uv0 = new Vector2((scale / 2) * (1 - Mathf.Cos(Mathf.PI / (180f / (i * 90 / segements)))), (1 - scale / 2) + (scale / 2) * Mathf.Sin(Mathf.PI / (180f / (i * 90 / segements))));
 64             }
 65                 uivertex.position = new Vector3(w * uivertex.uv0.x - w / 2, w * uivertex.uv0.y - w / 2);
 66             vh.AddVert(uivertex);
 67         }
 68 
 69         for (int i = 0; i < segements + 1; i++)
 70         {
 71             UIVertex uivertex = new UIVertex();
 72             uivertex.color = color;
 73             if (i == 0)
 74             {
 75                 uivertex.uv0 = new Vector2((1 - scale / 2) + (scale / 2) * Mathf.Sin(i * 90 / segements), (1 - scale / 2) + (scale / 2) * Mathf.Cos(i * 90 / segements));
 76             }
 77             else
 78             {
 79                 uivertex.uv0 = new Vector2( (1 - scale / 2) + (scale / 2) * Mathf.Sin(Mathf.PI / (180f / (i * 90 / segements))), (1 - scale / 2) + (scale / 2) * Mathf.Cos(Mathf.PI / (180f / (i * 90 / segements))));
 80 
 81             }
 82             uivertex.position = new Vector3(w * uivertex.uv0.x - w / 2, w * uivertex.uv0.y - w / 2);
 83             vh.AddVert(uivertex);
 84         }
 85         for (int i = 0; i < segements + 1; i++)
 86         {
 87             UIVertex uivertex = new UIVertex();
 88             uivertex.color = color;
 89             if (i == 0)
 90             {
 91                 uivertex.uv0 = new Vector2((1 - scale / 2) + (scale / 2) * Mathf.Cos(i * 90 / segements), (scale / 2) - (scale / 2) * Mathf.Sin(i * 90 / segements));
 92             }
 93             else
 94             {
 95                 uivertex.uv0 = new Vector2((1 - scale / 2) + (scale / 2) * Mathf.Cos(Mathf.PI / (180f / (i * 90 / segements))), (scale / 2) - (scale / 2) * Mathf.Sin(Mathf.PI / (180f / (i * 90 / segements))));
 96             }
 97                 uivertex.position = new Vector3(w * uivertex.uv0.x - w / 2, w * uivertex.uv0.y - w / 2);
 98             vh.AddVert(uivertex);
 99         }
100 
101         //((点*4+8个点-3)条弦+1)个三角形
102         for (int i = 0; i < ((segements - 1) * 4 + 8 - 3 + 1); i++)
103         {
104             vh.AddTriangle(0, i + 1, i + 2);
105         }
106         
107 
108     }
109 
110     public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
111     {
112         Sprite sprite = overrideSprite;
113         if (sprite == null)
114             return true;
115 
116         Vector2 local;
117         RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out local);
118         return Contains(local, outterVertices, innerVertices);
119     }
120 
121     private bool Contains(Vector2 p, List<Vector3> outterVertices, List<Vector3> innerVertices)
122     {
123         var crossNumber = 0;
124         RayCrossing(p, innerVertices, ref crossNumber);//检测内环
125         RayCrossing(p, outterVertices, ref crossNumber);//检测外环
126         return (crossNumber & 1) == 1;
127     }
128 
129     /// <summary>
130     /// 使用RayCrossing算法判断点击点是否在封闭多边形里
131     /// </summary>
132     /// <param name="p"></param>
133     /// <param name="vertices"></param>
134     /// <param name="crossNumber"></param>
135     private void RayCrossing(Vector2 p, List<Vector3> vertices, ref int crossNumber)
136     {
137         for (int i = 0, count = vertices.Count; i < count; i++)
138         {
139             var v1 = vertices[i];
140             var v2 = vertices[(i + 1) % count];
141 
142             //点击点水平线必须与两顶点线段相交
143             if (((v1.y <= p.y) && (v2.y > p.y))
144                 || ((v1.y > p.y) && (v2.y <= p.y)))
145             {
146                 //只考虑点击点右侧方向,点击点水平线与线段相交,且交点x > 点击点x,则crossNumber+1
147                 if (p.x < v1.x + (p.y - v1.y) / (v2.y - v1.y) * (v2.x - v1.x))
148                 {
149                     crossNumber += 1;
150                 }
151             }
152         }
153     }
154 
155 
156 }
View Code

 

unity之圆角头像实现