使用MaskableGraphic画线段-生成Mesh方式

发布时间 2023-06-18 15:39:40作者: 有间猫
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class UGUIPoplateMesh : MaskableGraphic, IPointerEnterHandler, IPointerExitHandler
{
    protected override void OnPopulateMesh(VertexHelper vh)
    {
        vh.Clear();

        for (int i = 0; i < vertexQuadList.Count; i++)
        {
            vh.AddUIVertexQuad(vertexQuadList[i]);
        }
    }

    List<UIVertex[]> vertexQuadList = new List<UIVertex[]>();
    Vector2 lastPoint = Vector2.zero;
    Vector2 lastLineVect = Vector2.zero;
    Vector3 lastNormal = Vector2.zero;
    bool isPointerInCavnas = false;
    bool isNewLine = false;
    bool isFirstPoint = true;
    public Camera uiCamera;
    public float width = 2f;
    
    protected override void Awake()
    {
        base.Awake();
        vertexQuadList.Clear();
    }

    void Update()
    {
        if(!isPointerInCavnas)
            return;

        if(Input.GetMouseButtonUp(2))
        {
            vertexQuadList.Clear();
            SetVerticesDirty();
            isFirstPoint = true;
            return;
        }

        if(Input.GetMouseButton(0))
        {
            var curPoint = GetScreenToLocalPoint(Input.mousePosition);
            if(isFirstPoint)
            {
                lastPoint = curPoint;
                isFirstPoint = false;
                isNewLine = true;
                return;
            }

            var vect = curPoint - lastPoint;

            if(vect.magnitude < 16)
                return;

            var normal3 = Vector3.Cross(vect, Vector3.forward).normalized;
            var normal = new Vector2(normal3.x, normal3.y);


            var lastUpPoint = lastPoint + normal * width;
            var lastDownPoint = lastPoint - normal * width;
            
            var curUpPoint = curPoint + normal * width;
            var curDownPoint = curPoint - normal * width;

            if(vertexQuadList.Count > 0)
            {
                // 获取上一个线段与当前绘制的线段的角度
                var angle = Vector3.Angle(lastLineVect, vect);
                // 如果不是平行的 在这之间补一个三角形
                if(angle != 0 || angle != 180)
                {
                    var array = vertexQuadList[vertexQuadList.Count - 1];

                    // 获取上边是否相交和相交的点
                    bool upinter = FindIntersectionPoint(array[0].position, array[3].position, lastUpPoint, curUpPoint, out var upinterPoint);
                    // 获取下边是否相交和相交的点
                    bool downinter = FindIntersectionPoint(array[1].position, array[2].position, lastDownPoint, curDownPoint, out var downinterPoint);

                    // 根据相交点判断如何找补三角形
                    if(upinter)
                    {
                        array[2].position = upinterPoint - width * lastNormal * 2;
                        array[3].position = upinterPoint;

                        lastUpPoint = upinterPoint;
                        lastDownPoint = upinterPoint - width * normal3 * 2;

                        
                        var vectQuad1 = new UIVertex[4];
                        vectQuad1[0] = GetUIVertex(upinterPoint);
                        vectQuad1[1] = GetUIVertex(array[2].position);
                        vectQuad1[2] = GetUIVertex(lastDownPoint);
                        vectQuad1[3] = GetUIVertex(upinterPoint);
                        vertexQuadList.Add(vectQuad1);
                    }
                    else if(downinter)
                    {
                        array[3].position = downinterPoint + width * lastNormal * 2;
                        array[2].position = downinterPoint;

                        lastUpPoint = downinterPoint + width * normal3 * 2;
                        lastDownPoint = downinterPoint;

                        
                        var vectQuad1 = new UIVertex[4];
                        vectQuad1[0] = GetUIVertex(array[3].position);
                        vectQuad1[1] = GetUIVertex(downinterPoint);
                        vectQuad1[2] = GetUIVertex(lastUpPoint);
                        vectQuad1[3] = GetUIVertex(array[3].position);
                        vertexQuadList.Add(vectQuad1);
                    }
                }
            }
            

            var vectQuad = new UIVertex[4];
            vectQuad[0] = GetUIVertex(lastUpPoint);
            vectQuad[1] = GetUIVertex(lastDownPoint);
            vectQuad[2] = GetUIVertex(curDownPoint);
            vectQuad[3] = GetUIVertex(curUpPoint);
            vertexQuadList.Add(vectQuad);
            
            lastNormal = normal;
            lastLineVect = vect.normalized;
            lastPoint = curPoint;
            lastUpPoint = curUpPoint;
            lastDownPoint = curDownPoint;
            CLog.Log(1, lastUpPoint, lastDownPoint);
            SetVerticesDirty();
        }   
    }

    bool FindIntersectionPoint(Vector3 A, Vector3 B, Vector3 C, Vector3 D , out Vector3 res)
    {
        Vector3 AB = B - A;
        Vector3 CD = D - C;
        res = Vector3.zero;
        float t1, t2;
        if (Vector3.Cross(AB, CD) == Vector3.zero)
        {
            // 矢量平行或共线,没有相交点
            Debug.Log("Vectors are parallel or collinear, no intersection point.");
            return false;
        }
        else
        {
            t1 = Vector3.Cross(C - A, CD).magnitude / Vector3.Cross(AB, CD).magnitude;
            t2 = Vector3.Cross(A - C, AB).magnitude / Vector3.Cross(CD, AB).magnitude;

            if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1)
            {
                // 有相交点
                res = A + t1 * AB;
                return true;
            }
            else
            {
                return false;
            }
        }
    }

    UIVertex GetUIVertex(Vector2 pos)
    {
        var uIVertex = new UIVertex();
        uIVertex.color = color;
        uIVertex.position = pos;
        return uIVertex;
    }



    Vector2 GetScreenToLocalPoint(Vector3 v3)
    {
        RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, v3, uiCamera, out var point);
        return point;
    }

    void IPointerEnterHandler.OnPointerEnter(PointerEventData eventData)
    {
        isPointerInCavnas = true;
    }

    void IPointerExitHandler.OnPointerExit(PointerEventData eventData)
    {        
        isPointerInCavnas = false;
    }
}