205 lines
7.5 KiB
C#
205 lines
7.5 KiB
C#
|
|
using System.Collections;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using UnityEngine;
|
||
|
|
using UnityEngine.Sprites;
|
||
|
|
using UnityEngine.UI;
|
||
|
|
|
||
|
|
#if UNITY_EDITOR
|
||
|
|
using UnityEditor;
|
||
|
|
using UnityEditor.UI;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/*
|
||
|
|
* @author 渡鸦
|
||
|
|
* @description 自定义顶点数据实现圆角矩形
|
||
|
|
* @公众号文档 https://mp.weixin.qq.com/s/FUO4xDmWmllryt2x7kVqig
|
||
|
|
*/
|
||
|
|
|
||
|
|
#if UNITY_EDITOR
|
||
|
|
[CustomEditor(typeof(BorderRadius), true)]
|
||
|
|
public class BorderRadiusEditor : ImageEditor
|
||
|
|
{
|
||
|
|
SerializedProperty _sprite;
|
||
|
|
SerializedProperty _cornerRadius;
|
||
|
|
SerializedProperty _cornerSegments;
|
||
|
|
|
||
|
|
protected override void OnEnable()
|
||
|
|
{
|
||
|
|
base.OnEnable();
|
||
|
|
|
||
|
|
this._sprite = this.serializedObject.FindProperty("m_Sprite");
|
||
|
|
this._cornerRadius = this.serializedObject.FindProperty("cornerRadius");
|
||
|
|
this._cornerSegments = this.serializedObject.FindProperty("cornerSegments");
|
||
|
|
}
|
||
|
|
|
||
|
|
public override void OnInspectorGUI()
|
||
|
|
{
|
||
|
|
this.serializedObject.Update();
|
||
|
|
|
||
|
|
this.SpriteGUI();
|
||
|
|
this.AppearanceControlsGUI();
|
||
|
|
this.RaycastControlsGUI();
|
||
|
|
bool showNativeSize = this._sprite.objectReferenceValue != null;
|
||
|
|
this.m_ShowNativeSize.target = showNativeSize;
|
||
|
|
this.MaskableControlsGUI();
|
||
|
|
this.NativeSizeButtonGUI();
|
||
|
|
EditorGUILayout.PropertyField(this._cornerRadius);
|
||
|
|
EditorGUILayout.PropertyField(this._cornerSegments);
|
||
|
|
EditorGUILayout.PropertyField(this.serializedObject.FindProperty("leftTop"));
|
||
|
|
EditorGUILayout.PropertyField(this.serializedObject.FindProperty("rightTop"));
|
||
|
|
EditorGUILayout.PropertyField(this.serializedObject.FindProperty("leftBottom"));
|
||
|
|
EditorGUILayout.PropertyField(this.serializedObject.FindProperty("rightBottom"));
|
||
|
|
this.serializedObject.ApplyModifiedProperties();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
public class BorderRadius : Image
|
||
|
|
{
|
||
|
|
public float cornerRadius = 8;
|
||
|
|
|
||
|
|
// 每个角最大的三角形数
|
||
|
|
[Range(1, 22)] public int cornerSegments = 8;
|
||
|
|
|
||
|
|
public bool leftTop = true;
|
||
|
|
public bool rightTop = true;
|
||
|
|
public bool leftBottom = true;
|
||
|
|
public bool rightBottom = true;
|
||
|
|
|
||
|
|
protected override void OnPopulateMesh(VertexHelper vh)
|
||
|
|
{
|
||
|
|
Rect rect = this.rectTransform.rect;
|
||
|
|
float left = rect.xMin;
|
||
|
|
float right = rect.xMax;
|
||
|
|
float top = rect.yMax;
|
||
|
|
float bottom = rect.yMin;
|
||
|
|
|
||
|
|
Vector4 outerUV = this.overrideSprite != null ? DataUtility.GetOuterUV(this.overrideSprite) : Vector4.zero;
|
||
|
|
var color32 = color;
|
||
|
|
float r = this.cornerRadius;
|
||
|
|
|
||
|
|
// 计算uv中对应的半径值坐标轴的半径
|
||
|
|
float uvRadiusX = r / (right - left) * (outerUV.z - outerUV.x);
|
||
|
|
float uvRadiusY = r / (top - bottom) * (outerUV.w - outerUV.y);
|
||
|
|
|
||
|
|
vh.Clear();
|
||
|
|
|
||
|
|
// 从左往右
|
||
|
|
// 0 1 2 3
|
||
|
|
vh.AddVert(new Vector3(left, top), color32, new Vector2(outerUV.x, outerUV.w));
|
||
|
|
vh.AddVert(new Vector3(left, top - r), color32, new Vector2(outerUV.x, outerUV.w - uvRadiusY));
|
||
|
|
vh.AddVert(new Vector3(left, bottom + r), color32, new Vector2(outerUV.x, outerUV.y + uvRadiusY));
|
||
|
|
vh.AddVert(new Vector3(left, bottom), color32, new Vector2(outerUV.x, outerUV.y));
|
||
|
|
|
||
|
|
// 4 5 6 7
|
||
|
|
vh.AddVert(new Vector3(left + r, top), color32, new Vector2(outerUV.x + uvRadiusX, outerUV.w));
|
||
|
|
vh.AddVert(new Vector3(left + r, top - r), color32,
|
||
|
|
new Vector2(outerUV.x + uvRadiusX, outerUV.w - uvRadiusY));
|
||
|
|
vh.AddVert(new Vector3(left + r, bottom + r), color32,
|
||
|
|
new Vector2(outerUV.x + uvRadiusX, outerUV.y + uvRadiusY));
|
||
|
|
vh.AddVert(new Vector3(left + r, bottom), color32, new Vector2(outerUV.x + uvRadiusX, outerUV.y));
|
||
|
|
|
||
|
|
// 8 9 10 11
|
||
|
|
vh.AddVert(new Vector3(right - r, top), color32, new Vector2(outerUV.z - uvRadiusX, outerUV.w));
|
||
|
|
vh.AddVert(new Vector3(right - r, top - r), color32,
|
||
|
|
new Vector2(outerUV.z - uvRadiusX, outerUV.w - uvRadiusY));
|
||
|
|
vh.AddVert(new Vector3(right - r, bottom + r), color32,
|
||
|
|
new Vector2(outerUV.z - uvRadiusX, outerUV.y + uvRadiusY));
|
||
|
|
vh.AddVert(new Vector3(right - r, bottom), color32, new Vector2(outerUV.z - uvRadiusX, outerUV.y));
|
||
|
|
|
||
|
|
// 12 13 14 15
|
||
|
|
vh.AddVert(new Vector3(right, top), color32, new Vector2(outerUV.z, outerUV.w));
|
||
|
|
vh.AddVert(new Vector3(right, top - r), color32, new Vector2(outerUV.z, outerUV.w - uvRadiusY));
|
||
|
|
vh.AddVert(new Vector3(right, bottom + r), color32, new Vector2(outerUV.z, outerUV.y + uvRadiusY));
|
||
|
|
vh.AddVert(new Vector3(right, bottom), color32, new Vector2(outerUV.z, outerUV.y));
|
||
|
|
|
||
|
|
// 左边矩形
|
||
|
|
vh.AddTriangle(2, 5, 1);
|
||
|
|
vh.AddTriangle(2, 5, 6);
|
||
|
|
// 中间矩形
|
||
|
|
vh.AddTriangle(7, 8, 4);
|
||
|
|
vh.AddTriangle(7, 8, 11);
|
||
|
|
// 右边矩形
|
||
|
|
vh.AddTriangle(10, 13, 9);
|
||
|
|
vh.AddTriangle(10, 13, 14);
|
||
|
|
|
||
|
|
List<Vector2> positionList = new List<Vector2>();
|
||
|
|
List<Vector2> uvList = new List<Vector2>();
|
||
|
|
List<int> vertexList = new List<int>();
|
||
|
|
|
||
|
|
// 右上角圆心
|
||
|
|
positionList.Add(new Vector2(right - r, top - r));
|
||
|
|
uvList.Add(new Vector2(outerUV.z - uvRadiusX, outerUV.w - uvRadiusY));
|
||
|
|
vertexList.Add(9);
|
||
|
|
|
||
|
|
// 左上角圆心
|
||
|
|
positionList.Add(new Vector2(left + r, top - r));
|
||
|
|
uvList.Add(new Vector2(outerUV.x + uvRadiusX, outerUV.w - uvRadiusY));
|
||
|
|
vertexList.Add(5);
|
||
|
|
|
||
|
|
// 左下角圆心
|
||
|
|
positionList.Add(new Vector2(left + r, bottom + r));
|
||
|
|
uvList.Add(new Vector2(outerUV.x + uvRadiusX, outerUV.y + uvRadiusY));
|
||
|
|
vertexList.Add(6);
|
||
|
|
|
||
|
|
// 右下角圆心
|
||
|
|
positionList.Add(new Vector2(right - r, bottom + r));
|
||
|
|
uvList.Add(new Vector2(outerUV.z - uvRadiusX, outerUV.y + uvRadiusY));
|
||
|
|
vertexList.Add(10);
|
||
|
|
|
||
|
|
// 每个三角形角度
|
||
|
|
float degreeDelta = Mathf.PI / 2 / this.cornerSegments;
|
||
|
|
|
||
|
|
// 当前角度
|
||
|
|
float degree = 0;
|
||
|
|
for (int i = 0; i < vertexList.Count; i++)
|
||
|
|
{
|
||
|
|
int currVertCount = vh.currentVertCount;
|
||
|
|
for (int j = 0; j <= this.cornerSegments; j++)
|
||
|
|
{
|
||
|
|
float cos = Mathf.Cos(degree);
|
||
|
|
float sin = Mathf.Sin(degree);
|
||
|
|
Vector3 position = new Vector3(positionList[i].x + cos * r, positionList[i].y + sin * r);
|
||
|
|
Vector3 uv0 = new Vector2(uvList[i].x + cos * uvRadiusX,
|
||
|
|
uvList[i].y + sin * uvRadiusY);
|
||
|
|
vh.AddVert(position, color32, uv0);
|
||
|
|
degree += degreeDelta;
|
||
|
|
}
|
||
|
|
|
||
|
|
degree -= degreeDelta;
|
||
|
|
|
||
|
|
if (i == 0 && !this.rightTop)
|
||
|
|
{
|
||
|
|
vh.AddTriangle(vertexList[i], 8, 12);
|
||
|
|
vh.AddTriangle(vertexList[i], 12, 13);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (i == 1 && !this.leftTop)
|
||
|
|
{
|
||
|
|
vh.AddTriangle(vertexList[i], 0, 4);
|
||
|
|
vh.AddTriangle(vertexList[i], 0, 1);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (i == 2 && !this.leftBottom)
|
||
|
|
{
|
||
|
|
vh.AddTriangle(vertexList[i], 3, 2);
|
||
|
|
vh.AddTriangle(vertexList[i], 3, 7);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (i == 3 && !this.rightBottom)
|
||
|
|
{
|
||
|
|
vh.AddTriangle(vertexList[i], 15, 14);
|
||
|
|
vh.AddTriangle(vertexList[i], 15, 11);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int j = 0; j <= this.cornerSegments - 1; j++)
|
||
|
|
{
|
||
|
|
vh.AddTriangle(vertexList[i], currVertCount + j + 1, currVertCount + j);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|