【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不會打斷

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