■前提

https://pgdays.com/index.php/unity/56-bspline

で作成したクラスを利用する

■サンプル(MonoBehaviour)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

public class BSplineRenderer : MaskableGraphic
{

    [SerializeField]
    private Vector3[] m_points;
    public Vector3[] points {
        get { return m_points; }
        set {
            m_points = value;
            Refresh();
        }
    }

    [SerializeField]
    private int m_degree;
    public int degree {
        get {
            return m_degree;
        }
        set {
            if (m_degree != value)
            {
                m_degree = value;
                Refresh();
            }
        }
    }

    [SerializeField]
    private BSpline.KnotType m_knotType;
    public BSpline.KnotType knotType {
        get {
            return m_knotType;
        }
        set {
            if (m_knotType != value)
            {
                m_knotType = value;
                Refresh();
            }
        }
    }

    [SerializeField]
    private int m_resolution;
    private int resolution {
        get {
            return m_resolution;
        }
        set {
            if (m_resolution != value)
            {
                m_resolution = value;
                Refresh();
            }
        }
    }

    [SerializeField]
    private bool m_enableBSpline = true;

    [SerializeField]
    private bool m_isLoop = false;

    [SerializeField]
    private float m_lineSize = 1;

    private List<Vector3> m_splinePoints = new List<Vector3>();

#if UNITY_EDITOR

    protected override void OnValidate()
    {
        base.OnValidate();
        Refresh();
    }

#endif

    protected override void OnPopulateMesh(VertexHelper vh)
    {
        vh.Clear();

        var points = m_splinePoints;

        if (m_lineSize <= 0 || m_points.Length < 2)
        {
            return;
        }

        var renderPoint = new List<UIVertex>();

        // 注意点:ローカル座標系を利用する
        int len = points.Count();
        UIVertex prevRightUp = UIVertex.simpleVert, prevRightDown = UIVertex.simpleVert;
        UIVertex firstLeftUp = UIVertex.simpleVert, firstLeftDown = UIVertex.simpleVert;
        for (int i = 0; i < len - 1; i++)
        {
            var start = points[i];
            var end = points[i + 1];

            // 単位法線に線幅/2を乗算する
            var offset = new Vector3(end.y - start.y, start.x - end.x, 0).normalized * m_lineSize / 2.0f;

            var vLeftUp = CreateUIVertex(start + offset, color);    // 左上
            var vRightUp = CreateUIVertex(end + offset, color);     // 右上
            var vRightDown = CreateUIVertex(end - offset, color);   // 右下
            var vLeftDown = CreateUIVertex(start - offset, color);  // 左下

            // 線の追加
            vh.AddUIVertexQuad(new UIVertex[] { vLeftDown, vLeftUp, vRightUp, vRightDown });

            // 線の切れ目対応
            if (i > 0)
            {
                var vtxList = new List<UIVertex> { prevRightUp, prevRightDown, vLeftUp, vLeftDown };
                vtxList.Sort((l,r)=>((int)(l.position.x-r.position.x)));
                vh.AddUIVertexQuad(CreateCap(vtxList));
            }

            // 0番目の線のLeftUp/LeftDownを保持しておく
            // -> Loop時の線の切れ目対策用
            if (i == 0)
            {
                firstLeftDown = vLeftUp;
                firstLeftUp = vLeftDown;
            }
            prevRightUp = vRightUp;
            prevRightDown = vRightDown;
        }

        // 最後の切れ目補正を行う
        if (m_knotType == BSpline.KnotType.OpenUniform && m_isLoop)
        {
            var vtxList = new List<UIVertex> { prevRightUp, prevRightDown, firstLeftUp, firstLeftDown };
            vtxList.Sort((l, r) => ((int)(l.position.x - r.position.x)));
            vh.AddUIVertexQuad(CreateCap(vtxList));
        }
    }

    private UIVertex[] CreateCap(List<UIVertex> vertex)
    {
        if (vertex.Count != 4)
            return vertex.ToArray();

        vertex.Sort((l, r) => ((int)(l.position.x - r.position.x)));

        UIVertex[] newVtx = new UIVertex[4];

        if (vertex[0].position.y >= vertex[1].position.y)
        {
            newVtx[0] = vertex[1];
            newVtx[1] = vertex[0];
        }
        else
        {
            newVtx[0] = vertex[0];
            newVtx[1] = vertex[1];
        }

        if (vertex[2].position.y >= vertex[3].position.y)
        {
            newVtx[2] = vertex[2];
            newVtx[3] = vertex[3];
        }
        else
        {
            newVtx[2] = vertex[3];
            newVtx[3] = vertex[2];
        }

        return newVtx;
    }

    private UIVertex CreateUIVertex(Vector3 vec, Color color)
    {
        var vtx = new UIVertex();
        vtx.position = vec;
        vtx.color = color;
        return vtx;
    }

    /// <summary>
    /// スプライン曲線を作成しなおす
    /// </summary>
    private void Refresh()
    {
        if (points.Count() <= 1)
        {
            m_splinePoints.Clear();
        }

        if (m_knotType == BSpline.KnotType.OpenUniform && m_isLoop)
        {
            var loopPoints = points.ToList();
            loopPoints.Add(loopPoints[0]);

            if (m_enableBSpline)
            {
                BSpline spline = new BSpline(loopPoints.ToArray(), m_degree, m_knotType);
                m_splinePoints = spline.evaluate(m_resolution);
            }
            else
            {
                m_splinePoints = loopPoints;
            }
        }
        else
        {
            if (m_enableBSpline)
            {
                BSpline spline = new BSpline(points, m_degree, m_knotType);
                m_splinePoints = spline.evaluate(m_resolution);
            }
            else
            {
                m_splinePoints = points.ToList();
            }
        }
    }
}

■サンプル(Editor)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(BSplineRenderer))]
public class BSplineRendererEditor : Editor {

    private bool m_isDrawLineOnEditor = true;
    private SerializedProperty m_points;
    private SerializedProperty m_degree;
    private SerializedProperty m_knotType;
    private SerializedProperty m_isLoop;

    private void OnEnable()
    {
        m_points = serializedObject.FindProperty("m_points");
        m_degree = serializedObject.FindProperty("m_degree");
        m_knotType = serializedObject.FindProperty("m_knotType");
        m_isLoop = serializedObject.FindProperty("m_isLoop");
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        m_isDrawLineOnEditor = EditorGUILayout.Toggle("IsDrawLineOnEditor",m_isDrawLineOnEditor);
    }

    private void OnSceneGUI()
    {
        var self = target as BSplineRenderer;

        // 内部キャッシュから最新のデータを取得
        serializedObject.Update();

        // Begin~, End~
        //  GUI グループ内のGUI要素でなんらかの変更がなされたときにアクションを起こすために使用する
        EditorGUI.BeginChangeCheck();

        var pointsForDrawLine = new List<Vector3>();
        var prevPoint = Vector3.zero;
        for(int i=0; i<m_points.arraySize; i++)
        {
            var prop = m_points.GetArrayElementAtIndex(i);

            // TransformPoint : local to world
            prop.vector3Value = Handles.DoPositionHandle(
                self.transform.TransformPoint(prop.vector3Value), 
                (target as BSplineRenderer).transform.rotation);
            pointsForDrawLine.Add(prop.vector3Value);

            if (m_isDrawLineOnEditor)
            {
                // 線引かないとつなぎ順がわかりにくいので線を引く
                if (i > 0)
                    Handles.DrawLine(pointsForDrawLine[i - 1], pointsForDrawLine[i]);
            } 

            // InverseTransformPoint: world to local
            prop.vector3Value = self.transform.InverseTransformPoint(prop.vector3Value);            
        }

        if (m_knotType.intValue == (int)BSpline.KnotType.OpenUniform && m_isLoop.boolValue)
        {
            if (m_points.arraySize > 0)
            {
                var v1 = self.transform.TransformPoint(m_points.GetArrayElementAtIndex(m_points.arraySize - 1).vector3Value);
                var v2 = self.transform.TransformPoint(m_points.GetArrayElementAtIndex(0).vector3Value);
                Handles.DrawLine(v1, v2);
            }
        }

        if (EditorGUI.EndChangeCheck())
        {
            // 内部キャッシュに変更点を適用する
            serializedObject.ApplyModifiedProperties();
        }
    }
}