Unity line drawing OnPopulateMesh function VertexHelper

About OnPopulateMesh function and VertexHelper class reference: OnPopulateMesh function and VertexHelper class of UGUI in Unity_Peter_Gao_’s Blog-CSDN Blog

A plugin for drawing charts (line charts, treemaps, pie charts, radar charts).

The bottom layer rewrites the OnPopulateMesh method in UGUI to realize the function of drawing lines with the mouse.

OnPopulateMesh(VertexHelper vh)
{

}

using System;
using System. Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public enum LineType
{
    Straight,
    smooth
}
 
public class DrawLineComponent : Graphic
{
    [Header("line properties")]
    [SerializeField] private LineType lineType = LineType. Straight;
    [SerializeField] private Line line = new StraightLine();
    [SerializeField] protected float m_ChartWidth;
    [NonSerialized] private bool m_RefreshChart = false;
    public float chartWidth { get { return m_ChartWidth; } }
    public LineType LineType
    {
        get => lineType;
        set
        {
            lineType = value;
            if (value == LineType. Straight)
                line = new StraightLine();
            else
                line = new SmoothLine();
            m_RefreshChart = true;
 
        }
    }
 
    protected override void Awake()
    {
        base. Awake();
        m_ChartWidth = rectTransform.sizeDelta.x;
        if (LineType == LineType. Smooth)
            line = new SmoothLine();
    }
    protected override void OnPopulateMesh(VertexHelper vh)
    {
        vh. Clear();
        line. DrawLine(vh);
    }
    private void Update()
    {
        CheckRefreshChart();
    }
    protected void CheckRefreshChart()
    {
        if (m_RefreshChart)
        {
            int tempWid = (int)chartWidth;
            rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, tempWid - 1);
            rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, tempWid);
            m_RefreshChart = false;
        }
    }
    public void AddPoint(Vector3 v3)
    {
        line.AddPoint(v3);
        m_RefreshChart = true;
    }
    public void AddPoint(List<Vector3> points)
    {
        line. AddPoint(points);
        m_RefreshChart = true;
 
    }
 
    public void SetSize(float size)
    {
        line.size = size;
        m_RefreshChart = true;
 
    }
    public void SetColor(Color color)
    {
        line.lineColor = color;
        m_RefreshChart = true;
 
    }
    public void SetSmoothness(float smoothness)
    {
        if (LineType == LineType. Smooth)
            ((SmoothLine)line). smoothness = smoothness;
 
        m_RefreshChart = true;
 
    }
    public void SetLineSmoothStyle(float smoothStyle)
    {
        if (LineType == LineType. Smooth)
            ((SmoothLine)line).lineSmoothStyle = smoothStyle;
        m_RefreshChart = true;
 
    }
}
 
[System. Serializable]
public class Line
{
    [SerializeField]
    protected List<Vector3> dataPoints = new List<Vector3>();
    [SerializeField] public float size = 1;
    [SerializeField] public Color lineColor = Color. black;
    public virtual void DrawLine(VertexHelper vh)
    {
    }
    public void AddPoint(Vector3 p)
    {
        dataPoints. Add(p);
    }
    public void AddPoint(List<Vector3> points)
    {
        dataPoints. AddRange(points);
    }
}
public class StraightLine : Line
{
    public override void DrawLine(VertexHelper vh)
    {
        for (int i = 0; i < dataPoints. Count; i ++ )
        {
            if (i < dataPoints. Count - 1)
            {
                UIDrawLine.DrawLine(vh, dataPoints[i], dataPoints[i + 1], size, lineColor);
            }
        }
    }
}
public class SmoothLine:Line
{
    /// <summary>
    // Curve smoothness. The smaller the value, the smoother the curve, but the number of vertices will increase accordingly.
    /// </summary>
    [SerializeField] public float smoothness = 2;
    /// <summary>
    /// Curve smoothing factor. The curvature of the curve can be changed by adjusting the smoothing factor, resulting in a different curve with a slightly different appearance.
    /// </summary>
    [SerializeField] public float lineSmoothStyle = 2;
 
 
    private List<Vector3> bezierPoints = new List<Vector3>();
    public override void DrawLine(VertexHelper vh)
    {
        Vector3 lp = Vector3.zero;
        Vector3 np = Vector3.zero;
        Vector3 llp = Vector3.zero;
        Vector3 nnp = Vector3.zero;
 
        for (int i = 0; i < dataPoints. Count; i ++ )
        {
            if (i < dataPoints. Count - 1)
            {
                llp = i > 1 ? dataPoints[i - 2] : lp;
                nnp = i < dataPoints.Count - 1 ? dataPoints[i + 1] : np;
                UIDrawLine.GetBezierList(ref bezierPoints, dataPoints[i], dataPoints[i + 1], llp, nnp, smoothness, lineSmoothStyle);
                for (int j = 0; j < bezierPoints. Count; j ++ )
                {
                    if (j < bezierPoints. Count - 1)
                    {
                        UIDrawLine.DrawLine(vh, bezierPoints[j], bezierPoints[j + 1], size, lineColor);
                    }
                }
            }
        }
    }
 
 
}
 
 

line drawing script

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// draw line
/// https://github.com/monitor1394/unity-ugui-XCharts
/// </summary>
public class UIDrawLine
{
    private static UIVertex[] vertex = new UIVertex[4];
    public static void DrawLine(VertexHelper vh, Vector3 p1, Vector3 p2, float size, Color32 color)
    {
        if (p1 == p2) return;
        Vector3 v = Vector3.Cross(p2 - p1, Vector3.forward).normalized * size;
        vertex[0].position = p1 - v;
        vertex[1].position = p2 - v;
        vertex[2].position = p2 + v;
        vertex[3].position = p1 + v;
 
        for (int j = 0; j < 4; j ++ )
        {
            vertex[j].color = color;
            vertex[j].uv0 = Vector2.zero;
        }
        vh. AddUIVertexQuad(vertex);
    }
 
 
 
    public static void GetBezierList(ref List<Vector3> posList, Vector3 sp, Vector3 ep,
           Vector3 lsp, Vector3 nep, float smoothness = 2f, float k = 2.0f)
    {
        float dist = Mathf.Abs(sp.x - ep.x);
        Vector3 cp1, cp2;
        var dir = (ep - sp).normalized;
        var diff = dist /k;
        if (lsp == sp)
        {
            cp1 = sp + dist / k * dir * 1;
            cp1.y = sp.y;
            cp1 = sp;
        }
        else
        {
            cp1 = sp + (ep - lsp).normalized * diff;
        }
        if (nep == ep) cp2 = ep;
        else cp2 = ep - (nep - sp).normalized * diff;
        dist = Vector3.Distance(sp, ep);
        int segment = (int)(dist / (smoothness <= 0 ? 2f : smoothness));
        if (segment < 1) segment = (int)(dist / 0.5f);
        if (segment < 4) segment = 4;
        GetBezierList2(ref posList, sp, ep, segment, cp1, cp2);
    }
    public static void GetBezierList2(ref List<Vector3> posList, Vector3 sp, Vector3 ep, int segment, Vector3 cp,
          Vector3 cp2)
    {
        posList. Clear();
        if (posList. Capacity < segment + 1)
        {
            posList. Capacity = segment + 1;
        }
        for (int i = 0; i < segment; i ++ )
        {
            posList.Add((GetBezier2(i / (float)segment, sp, cp, cp2, ep)));
        }
        posList. Add(ep);
    }
    public static Vector3 GetBezier2(float t, Vector3 sp, Vector3 p1, Vector3 p2, Vector3 ep)
    {
        t = Mathf. Clamp01(t);
        var oneMinusT = 1f - t;
        return oneMinusT * oneMinusT * oneMinusT * sp +
            3f * oneMinusT * oneMinusT * t * p1 +
            3f * oneMinusT * t * t * p2 +
            t * t * t * ep;
    }
}
public class TestMouse : MonoBehaviour
{
    [SerializeField] private DrawLineComponent dl;
    void Start()
    {
        dl. SetSize(2);
    }
 
    void Update()
    {
        if(Input. GetMouseButton(0))
        {
            Debug. Log(Input. mousePosition);
            dl.AddPoint(Input.mousePosition);
        }
    }
}