Unity贝塞尔曲线

贝塞尔曲线,简单就是对点之间连续进行插值,最后剩下两个点之后的计算结果

即如点A,B,C,D,E,对这些点进行两两插值,如A1=AB,即A1是对A和B进行插值后的结果

A1=AB,B1=BC,C1=CD,D1=DE

A2=A1B1,B2=B1C1,C2=C1D1

A3=A2B2,B3=B2C2

Result=A3B3

 

这里贴上我认为的比较好的一个仁兄的博客地址:https://blog.csdn.net/qq_35539447/article/details/80486247

下面是我的代码

using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bezier : MonoBehaviour
{
    /// <summary>
    /// 三个控制点的贝塞尔曲线
    /// </summary>
    /// <param name="handles"></param>
    /// <param name="vertexCount"></param>
    /// <returns>返回贝塞尔曲线路径点表</returns>
    public static List<Vector3> BezierCurveWithThree(Transform[] handles,int vertexCount)
    {
        List<Vector3> pointList = new List<Vector3>();
        for (float ratio = 0; ratio <= 1; ratio += 1.0f / vertexCount)
        {
            Vector3 tangentLineVertex1 = Vector3.Lerp(handles[0].position, handles[1].position, ratio);
            Vector3 tangentLineVertex2 = Vector3.Lerp(handles[1].position, handles[2].position, ratio);
            Vector3 bezierPoint = Vector3.Lerp(tangentLineVertex1, tangentLineVertex2, ratio);
            pointList.Add(bezierPoint);
        }
        pointList.Add(handles[2].position);

        return pointList;
    }

    /// <summary>
    /// 超过三个控制点的贝塞尔曲线
    /// </summary>
    /// <param name="handlesPositions"></param>
    /// <param name="vertexCount"></param>
    public static List<Vector3> BezierCurveWithUnlimitPoints(Transform[] handlesPositions,int vertexCount)
    {
        List<Vector3> pointList = new List<Vector3>();
        for (float ratio = 0; ratio <= 1; ratio += 1.0f / vertexCount)
        {
            pointList.Add(UnlimitBezierCurve(handlesPositions, ratio));
        }
        pointList.Add(handlesPositions[handlesPositions.Length - 1].position);

        return pointList;
    }
    public static Vector3 UnlimitBezierCurve(Transform[] trans, float t)
    {
        Vector3[] temp = new Vector3[trans.Length];
        for (int i = 0; i < temp.Length; i++)
        {
            temp[i] = trans[i].position;
        }
        int n = temp.Length - 1;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n - i; j++)
            {
                temp[j] = Vector3.Lerp(temp[j], temp[j + 1], t);
            }
        }
        return temp[0];
    }
}

贝塞尔曲线动态组件代码

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

public class BezierController : MonoBehaviour
{
    public bool isRunning;
    public bool isShowGizmos;
    public bool isShowLineRenderer;
    public bool isShowFixedPoints;
    [Header("控制手柄")]
    public Transform[] handles;
    Vector3[] handlesOriginalPoint;//控制带你的原始位置
    public int vertexCount;
    List<Vector3> pointList = new List<Vector3>();
    [Header("固定点距离点集合")]
    public List<Vector3> fixedSpacePoints = new List<Vector3>();
    public float fixedSpace;
    [Header("线渲染工具")]
    public LineRenderer lineRenderer;

    private void Start()
    {
        handlesOriginalPoint = new Vector3[handles.Length];
        for(int i = 0; i < handles.Length; i++)
        {
            handlesOriginalPoint[i] = handles[i].position;
        }
        Running();
    }
    
    private void Update()
    {
        if (CheckHandlesMove()&&isRunning)
        {
            Running();
        }
    }

    void Running()
    {
        pointList = Bezier.BezierCurveWithUnlimitPoints(handles, vertexCount);
        fixedSpacePoints = MathTools.GetEqualySpacePoints(pointList, fixedSpace);

        if (isShowLineRenderer) {
            lineRenderer.positionCount = pointList.Count;
            lineRenderer.SetPositions(pointList.ToArray());
        }
    }

    //获取路径点
    public List<Vector3> GetPointList()
    {
        return Bezier.BezierCurveWithUnlimitPoints(handles, vertexCount);
    }

    //获取固定间隔距离位置
    public List<Vector3> GetFixedSpacePoints()
    {
        CheckHandlesMove();
        List<Vector3> list = Bezier.BezierCurveWithUnlimitPoints(handles, vertexCount);
        return MathTools.GetEqualySpacePoints(list, fixedSpace);
    }

    //控制点是否发生更新: 是否改变了控制点的数量或者控制点是否发生了位移
    bool CheckHandlesMove()
    {
        bool hasMove = false;

        if(handlesOriginalPoint==null)handlesOriginalPoint = new Vector3[]{};
        if (handlesOriginalPoint.Length != handles.Length)
        {
            handlesOriginalPoint = new Vector3[handles.Length];
            for (int i = 0; i < handles.Length; i++)
            {
                handlesOriginalPoint[i] = handles[i].position;
            }
            return true;
        }

        for(int i = 0; i < handles.Length; i++)
        {
            if(handles[i].position!= handlesOriginalPoint[i])
            {
                hasMove = true;
                break;
            }
        }
        return hasMove;
    }

    private void OnDrawGizmos()
    {
        if (isShowGizmos) {
            if (handles.Length > 3)
            {
                #region 无限制顶点数

                Gizmos.color = Color.green;

                for (int i = 0; i < handles.Length - 1; i++)
                {
                    Gizmos.DrawLine(handles[i].position, handles[i + 1].position);
                }

                Gizmos.color = Color.red;

                Vector3[] temp = new Vector3[handles.Length];
                for (int i = 0; i < temp.Length; i++)
                {
                    temp[i] = handles[i].position;
                }
                int n = temp.Length - 1;
                for (float ratio = 0.5f / vertexCount; ratio < 1; ratio += 1.0f / vertexCount)
                {
                    for (int i = 0; i < n - 2; i++)
                    {
                        Gizmos.DrawLine(Vector3.Lerp(temp[i], temp[i + 1], ratio), Vector3.Lerp(temp[i + 2], temp[i + 3], ratio));
                    }
                }
                #endregion
            }
            else
            {
                #region 顶点数为3

                Gizmos.color = Color.green;

                Gizmos.DrawLine(handles[0].position, handles[1].position);

                Gizmos.color = Color.green;

                Gizmos.DrawLine(handles[1].position, handles[2].position);

                Gizmos.color = Color.red;

                for (float ratio = 0.5f / vertexCount; ratio < 1; ratio += 1.0f / vertexCount)
                {

                    Gizmos.DrawLine(Vector3.Lerp(handles[0].position, handles[1].position, ratio), Vector3.Lerp(handles[1].position, handles[2].position, ratio));

                }

                #endregion
            }
        }

        if (isShowFixedPoints) {
            #region 显示固定距离的点列表
            Gizmos.color = Color.green;
            foreach (Vector3 point in fixedSpacePoints)
            {
                Gizmos.DrawSphere(point, 0.3f);
            }
            #endregion
        }

    }
}

上面的MathTool看我的另一个博客文章unity数学工具

 

posted @ 2020-11-08 01:12  小辉歌  阅读(1265)  评论(0编辑  收藏  举报