参考了这篇文章:https://www.cnblogs.com/leoin2012/p/6425089.html
但是这篇文章写的时间比较早,UGUI到现在有很多改动了,这里写了一个优化版的,用法类似Outline,在Image节点上直接挂上去就能用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditor.Sprites;
using UnityEngine;
using UnityEngine.UI;
[AddComponentMenu("UI/Effects/Circle", 16)]
[RequireComponent(typeof(Image))]
public class Circle : BaseMeshEffect
{
private int segementCount = 100; //将圆绘制成的3角块数
private int circleVertexCount; //圆顶点的数量
private RectTransform rectTransform = null;
private Image image = null;
public override void ModifyMesh(VertexHelper vh)
{
if (!isActiveAndEnabled) return;
if (rectTransform == null)
{
rectTransform = GetComponent<RectTransform>();
}
if (image == null)
{
image = GetComponent<Image>();
}
if (image.type != Image.Type.Simple)
{
return;
}
Sprite sprite = image.overrideSprite;
if (sprite == null || image.overrideSprite == null)
{
return;
}
float width = rectTransform.rect.width;
float height = rectTransform.rect.height;
float maxSide = Mathf.Max(width, height);
// lod
if (maxSide > 512)
segementCount = 60;
else if (maxSide > 256)
segementCount = 50;
else if (maxSide > 128)
segementCount = 30;
else if (maxSide > 64)
segementCount = 25;
else if (maxSide > 32)
segementCount = 20;
else
segementCount = 15;
circleVertexCount = segementCount + 2; //渲染圆所需要的顶点数
vh.Clear();
Vector2[] uvs = image.overrideSprite.uv;// SpriteUtility.GetSpriteUVs(image.overrideSprite, false);
float minX = 10000, minY = 10000, maxX = -10000, maxY = -10000;
for (int i = 0; i < uvs.Length; ++i)
{
var uv = uvs[i];
minX = Mathf.Min(minX, uv.x);
maxX = Mathf.Max(maxX, uv.x);
minY = Mathf.Min(minY, uv.y);
maxY = Mathf.Max(maxY, uv.y);
}
//利用当前UV座标计算出uvCenter的座标(uvCenterX,uvCenterY)
float uvCenterX = (minX + maxX) * 0.5f;
float uvCenterY = (minY + maxY) * 0.5f;
//利用当前Image的宽高和UV宽高计算出 X,Y轴上的UV转换系数(uvScaleX,uvScaleY)(每1单位的position所占的uv值)
float uvScaleX = (maxX - minX) / width;
float uvScaleY = (maxY - minY) / height;
//求每一块段区域所占圆的弧度(radian)与绘制的圆的半径(radius)
float radian = 2 * Mathf.PI / segementCount;
float radius = rectTransform.pivot.x * width;
//创建圆心顶点,并给出Position,color,uv0座标
UIVertex centerVertex = new UIVertex();
centerVertex.position = Vector2.zero; //这个座标主要用于作为其他顶点的座标参照。
centerVertex.color = image.color;
centerVertex.uv0 = new Vector2(uvCenterX, uvCenterY);
vh.AddVert(centerVertex);
float curRadian = 0; //记作当前弧度,并添加其余圆弧上的顶点
for (int i = 0; i < circleVertexCount - 1; i++)
{
UIVertex vertex = new UIVertex();
float x = Mathf.Cos(curRadian) * radius;
float y = Mathf.Sin(curRadian) * radius;
vertex.position = new Vector2(centerVertex.position.x + x, centerVertex.position.y + y);
vertex.color = image.color;
var uv_x = x * uvScaleX + uvCenterX;
var uv_y = y * uvScaleY + uvCenterY;
vertex.uv0 = new Vector2(uv_x, uv_y); //与uvCenter的uv偏移量+uvCenter
vh.AddVert(vertex);
curRadian += radian;
}
//vertexHelper添加3角面信息,在渲染流程中,以3个顶点顺时针添加的面渲染,3个顶点逆时针添加的面不渲染
for (int i = 1; i < circleVertexCount - 1; i++)
{
vh.AddTriangle(i, 0, i + 1);
}
}
}
效果如图
有缺陷 只适合正方形或者没有打成图集的图片,因为非正方形打成图集的,会采样到其他图片上
有优势 无需使用裁剪,Drawcall不会打断