參考了這篇文章: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不會打斷