目标任务:实现一个圆形面片的Image,实现效果如下:
为什么要实现这个东西呢,其实原先在做这种圆形效果的时候都是在用Mask实现的(相信很多都是这样的~(罒ω罒)),但是最近了解了下优化方面的知识,发现Mask还是很占用DrawCall的,所以本着精益求精的 态度,学习了下怎么自己做一个圆形的Image。
这里可能先要了解一下Image是怎么渲染出来的,具体的我就不说了,就说个简单的,我们生成一个Cube,我们可以看到他的网格是由很多三角形拼起来的,而其中每一个三角形是由三个顶点组成的,我们要做的其实就是生成多个这样的三角形来组成一个圆形(这里还要说下这样的三角形面片的正反面,在我们设置顶点的时候,顶点输入顺序是应该按照顺时针输入的,这样我们才会看见生成的面,不然会变成透明的样子,不信可以试下~~~)。
代码如下
using UnityEngine;
using UnityEngine.Sprites;
using UnityEngine.UI;public class CircleImage : Image {private int segements;//圆形由多少个三角形拼成protected override void OnPopulateMesh(VertexHelper vh){segements = 100;vh.Clear();//图片宽高float width = rectTransform.rect.width;float height = rectTransform.rect.height;Vector4 uv = overrideSprite != null ? DataUtility.GetOuterUV(overrideSprite) : Vector4.zero;//uv宽高float uvWidth = (uv.z - uv.x) * 0.5f;float uvHeight = (uv.w - uv.y) * 0.5f;//贴图的中心点Vector2 uvCenter = new Vector2(uvWidth, uvHeight);//uv转Pos坐标转换系数(不懂得可以试下让UVで宽高乘以零点几)Vector2 converRatio = new Vector2(uvWidth/width,uvHeight/height);//求每一个三角形的弧度 公式:2π/个数float radian = (2 * Mathf.PI) / segements;//设置半径float radius = width * 0.5f;UIVertex origin = new UIVertex();origin.color = color;origin.position = Vector3.zero;//获取到当前原点的UV坐标origin.uv0 = new Vector2(origin.position.x * converRatio.x+uvCenter.x, origin.position.y * converRatio.y+uvCenter.y);//添加顶点信息vh.AddVert(origin);//顶点数量int vertexCount = segements + 1;//当前弧度float curRadian = 0;for (int i = 0; i < vertexCount; i++){float x = Mathf.Cos(curRadian) * radius;float y = Mathf.Sin(curRadian) * radius;curRadian += radian;//生成顶点UIVertex vertexTemp = new UIVertex();vertexTemp.color = color;vertexTemp.position = new Vector2(x,y);vertexTemp.uv0 = new Vector2(vertexTemp.position.x * converRatio.x+uvCenter.x, vertexTemp.position.y * converRatio.y+uvCenter.y);vh.AddVert(vertexTemp);}//生成面片int id = 1;for (int i = 0; i < segements; i++){//id从1开始递增,设置三角形vh.AddTriangle(id,0,id+1);id++;}}
}