思路
- 绘制圆 ,使用多个三角形组合在一起近似一个圆
- 单位圆上的点使用(Cosx,Sinx)表示
- sprite的uv映射到单位圆上
点到UV的映射规律
Sprite的外部uv 为 (x y z w ) 原点为 (x,y) 宽度为z-x 高度为w-y
单位圆上的点为(CosA,SinA)
uv坐标 = (x,y) + (CosA*(z-x)/2+(z-x)/2 ,SinA*(w-y)/2+(w-y)/2);
例如 圆上的点为(1,0) uv为(0,0.1,1)
对应的uv为 (0,0) + (1*(1-0)/2+(1-0)/2 ,0*(1-0)/2+(1-0)/2)=(1,0.5)
代码示例
using UnityEngine;
using UnityEngine.Sprites;
using UnityEngine.UI;
public class ImageCircle : Image
{protected override void OnPopulateMesh(VertexHelper toFill){toFill.Clear();//清除顶点Vector4 SpriteUV = overrideSprite != null ? DataUtility.GetOuterUV(overrideSprite) : Vector4.zero;Vector2 UVSize = new Vector2(SpriteUV.z - SpriteUV.x, SpriteUV.w - SpriteUV.y);//获取精灵uv 宽高Vector2 UVOrigion = new Vector2(SpriteUV.x, SpriteUV.y);//uv原点Vector2 UVHalfSize = UVSize / 2;Vector2 CenterUV = UVOrigion + UVHalfSize;Vector2 roundPoint = rectTransform.rect.center;//圆心toFill.AddVert(roundPoint, color, CenterUV);float width = rectTransform.rect.width;//image 矩形框的宽度float height = rectTransform.rect.height;float radius = width > height ? height / 2 : width / 2;//半径 取较小值int triangleCount = 100;//组成圆的三角形数量float singleAngle = 2 * Mathf.PI / triangleCount;//单个三角形顶点角度Vector2 pointInCircle;Vector2 pointToUV;float currentAngle;for (int i = 0; i < triangleCount + 1; i++)//获取圆上的点 圆上的点比三角形数量多1{currentAngle = i * singleAngle;//当前角度pointInCircle = new Vector2(Mathf.Cos(currentAngle), Mathf.Sin(currentAngle));//单位圆上的点pointToUV = UVOrigion +new Vector2(pointInCircle.x * UVHalfSize.x + UVHalfSize.x,pointInCircle.y * UVHalfSize.y + UVHalfSize.y);//点对应的uvtoFill.AddVert(roundPoint + pointInCircle * radius, color, pointToUV);}for (int i = 0; i < triangleCount; i++)//绘制三角形{toFill.AddTriangle(i + 1, 0, i + 2);}}private void OnDrawGizmos(){Gizmos.DrawCube(rectTransform.localPosition, Vector3.one);}
}
参考
Unity用OnPopulateMesh绘制自定义圆形遮罩超详解