【UGUI】基于Mesh的单一图片裁剪

参考了这篇文章:https://www.cnblogs.com/leoin2012/p/6425089.html

这篇文章的源码在这里:https://github.com/HanxianshengGame/UGUI_CircleImage/blob/master/SampleScene/Assets/_MyScripts/Example%202.1/CircleImageSolution%20%20%20%EF%BC%88%E5%88%B6%E4%BD%9C%E5%9C%86%E5%BD%A2Image%E7%BB%84%E4%BB%B6%EF%BC%89/CircleImage.cs

 

但是这篇文章写的时间比较早,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不会打断

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章