BezierCurve-Unity中创建贝塞尔曲线

2018-06-23  本文已影响0人  Replay923

Foreword

好记性不如烂笔头。

BezierCurve简介

在数学的数值分析领域中,贝塞尔曲线(英语:Bézier curve,亦作“贝塞尔”)是计算机图形学中相当重要的参数曲线。更高维度的广泛化贝塞尔曲线就称作贝塞尔曲面,其中贝塞尔三角是一种特殊的实例。 —— 维基百科
。本篇只讨论曲线。

构建Bezier曲线

应用与代码

二次贝塞尔曲线

//pointList 为顶点集合。 point1,point2,point3 为构建曲线的三个顶点

//Vector3.Lerp 为 UnityEngine 中的API。通过传入两点和之间的插值(0~1)得到一个新的三维向量

//vertexCount 为构建曲线的顶点数,此数值越大曲线越平滑

public static Vector3[] GetBezierCurveWithThreePoints(Vector3 point_1, Vector3 point_2, Vector3 point_3, int vertexCount)
{
    List<Vector3> pointList = new List<Vector3>();
    for (float ratio = 0; ratio <= 1; ratio += 1.0f / vertexCount)
    {
        //首先取前两个点和后两个点的线性插值。

        Vector3 tangentLineVertex1 = Vector3.Lerp(point_1, point_2, ratio);
        Vector3 tangentLineVertex2 = Vector3.Lerp(point_2, point_3, ratio);
        //通过计算两个点的插值得到曲线的顶点

        Vector3 bezierPoint = Vector3.Lerp(tangentLineVertex1, tangentLineVertex2, ratio);
        pointList.Add(bezierPoint);
    }
    pointList.Add(point_3);
    return pointList.ToArray();
}

二次贝塞尔曲线unity中演示效果

二次贝塞尔曲线演示动画

高阶贝塞尔曲线

//传入顶点集合,得到高阶的贝塞尔曲线,顶点数量不限

//vertexCount 为构建曲线的顶点数,此数值越大曲线越平滑

public static Vector3[] GetBezierCurveWithUnlimitPoints(Vector3[] vertex, int vertexCount)
{
    List<Vector3> pointList = new List<Vector3>();
    pointList.Clear();
    for (float ratio = 0; ratio <= 1; ratio += 1.0f / vertexCount)
    {
        pointList.Add(UnlimitBezierCurve(vertex, ratio));
    }
    pointList.Add(vertex[vertex.Length - 1]);

    return pointList.ToArray();
}

public static Vector3 UnlimitBezierCurve(Vector3[] vecs, float t)
{
    Vector3[] temp = new Vector3[vecs.Length];
    for (int i = 0; i < temp.Length; i++)
    {
        temp[i] = vecs[i];
    }
    //顶点集合有多长,曲线的每一个点就需要计算多少次。

    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];
}

高阶贝塞尔曲线unity中演示效果

高阶贝塞尔曲线演示动画

整体脚本代码

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

[ExecuteInEditMode]
public class BezierCurvePointRenderer : MonoBehaviour
{

    public Transform point1;
    public Transform point2;
    public Transform point3;
    public LineRenderer lineRenderer;
    public int vertexCount;

    public Transform[] positions;

    private List<Vector3> pointList;
    private void Start()
    {
        pointList = new List<Vector3>();
    }
    private void Update()
    {
        //BezierCurveWithThree();

        BezierCurveWithUnlimitPoints();

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

    private void BezierCurveWithThree()
    {
        pointList.Clear();
        for (float ratio = 0; ratio <= 1; ratio += 1.0f / vertexCount)
        {
            Vector3 tangentLineVertex1 = Vector3.Lerp(point1.position, point2.position, ratio);
            Vector3 tangentLineVertex2 = Vector3.Lerp(point2.position, point3.position, ratio);
            Vector3 bezierPoint = Vector3.Lerp(tangentLineVertex1, tangentLineVertex2, ratio);
            pointList.Add(bezierPoint);
        }
        pointList.Add(point3.position);
    }

    public void BezierCurveWithUnlimitPoints()
    {
        pointList.Clear();
        for (float ratio = 0; ratio <= 1; ratio += 1.0f / vertexCount)
        {
            pointList.Add(UnlimitBezierCurve(positions, ratio));
        }
        pointList.Add(positions[positions.Length - 1].position);
    }
    public 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];
    }

    private void OnDrawGizmos()
    {


        #region 无限制顶点数

        Gizmos.color = Color.green;

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

        Gizmos.color = Color.red;

        Vector3[] temp = new Vector3[positions.Length];
        for (int i = 0; i < temp.Length; i++)
        {
            temp[i] = positions[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

        //#region 顶点数为3

        //Gizmos.color = Color.green;

        //Gizmos.DrawLine(point1.position, point2.position);

        //Gizmos.color = Color.green;

        //Gizmos.DrawLine(point2.position, point3.position);

        //Gizmos.color = Color.red;

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

        //    Gizmos.DrawLine(Vector3.Lerp(point1.position, point2.position, ratio), Vector3.Lerp(point2.position, point3.position, ratio));

        //} 
        
        //#endregion
    }
}


上一篇下一篇

猜你喜欢

热点阅读