目标任务:实现一个圆形面片的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++;
}
}
}