一:前言
一条贝塞尔曲线是由一组定义的控制点P0到 Pn,n=1为线性,n=2为二次......第一个和最后一个控制点称为起点和终点,中间的控制点一般不会位于曲线上
获取两个点之间的点就是通过线性插值( Mathf.Lerp),0 <= t <= 1
二:贝塞尔曲线公式
——线性公式:给定点P0、P1,线性贝兹曲线只是一条两点之间的直线。这条线由下式给出
——二阶贝塞尔曲线:二次方贝塞尔曲线的路径由给定点P0、P1、P2的函数B(t)公式推导:由(P0,P1),(P1,P2)分别求线性公式所得的结果P0‘ 和 P1‘再带入线性公式,整理所得即为二次公式
P0,P1所求:
P1,P2所求:
P0,P1,P2二次方公式:
简化所得
——三阶贝塞尔曲线:P0、P1、P2、P3四个点在平面或在三维空间中定义了三次方贝兹曲线。曲线起始于P0走向P1,并从P2的方向来到P3。一般不会经过P1或P2;这两个点只是在那里提供方向。P0和P1之间的间距,决定了曲线在转而趋进P3之前,走向P2方向的“长度有多长”。
其公式为
三:公式转换为代码
using UnityEngine;
/// <summary>
/// 贝塞尔工具类
/// </summary>
public static class BezierUtils
{
/// <summary>
/// 线性贝塞尔曲线
/// </summary>
public static Vector3 BezierCurve(Vector3 p0, Vector3 p1, float t)
{
Vector3 B = Vector3.zero;
B = (1 - t) * p0 + t * p1;
return B;
}
/// <summary>
/// 二阶贝塞尔曲线
/// </summary>
public static Vector3 BezierCurve(Vector3 p0, Vector3 p1, Vector3 p2, float t)
{
Vector3 B = Vector3.zero;
float t1 = (1 - t) * (1 - t);
float t2 = 2 * t * (1 - t);
float t3 = t * t;
B = t1 * p0 + t2 * p1 + t3 * p2;
return B;
}
/// <summary>
/// 三阶贝塞尔曲线
/// </summary>
public static Vector3 BezierCurve(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
{
Vector3 B = Vector3.zero;
float t1 = (1 - t) * (1 - t) * (1 - t);
float t2 = 3 * t * (1 - t) * (1 - t);
float t3 = 3 * t * t * (1 - t);
float t4 = t * t * t;
B = t1 * p0 + t2 * p1 + t3 * p2 + t4 * p3;
return B;
}
}
四:绘制出曲线
using System.Collections.Generic;
using UnityEngine;
public class BezierTest : MonoBehaviour
{
public int m_CurveDensity;//曲线密度
public bool m_IsSecondOrderBezier;//是否为二阶贝塞尔曲线,否则为三阶贝塞尔曲线
private List<Transform> m_ControlPointList = new List<Transform>();//所有的控制点(控制点作为挂载此脚本的游戏物体的子物体)
public void OnDrawGizmos()
{
//添加控制点
m_ControlPointList.Clear();
foreach (Transform trans in transform)
{
m_ControlPointList.Add(trans);
}
List<Vector3> pointList = new List<Vector3>();//曲线上的所有点
if (m_IsSecondOrderBezier)
{
if (m_ControlPointList.Count < 3)
{
return;
}
//获取曲线上的所有点
for (int i = 0; i < m_ControlPointList.Count - 2; i += 2)
{
Vector3 p0 = m_ControlPointList[i].position;
Vector3 p1 = m_ControlPointList[i + 1].position;
Vector3 p2 = m_ControlPointList[i + 2].position;
for (int j = 0; j <= m_CurveDensity; j++)
{
float t = j * 1f / m_CurveDensity;
Vector3 point = BezierUtils.BezierCurve(p0, p1, p2, t);
pointList.Add(point);
}
}
}
else
{
if (m_ControlPointList.Count < 4)
{
return;
}
//获取曲线上的所有点
for (int i = 0; i < m_ControlPointList.Count - 3; i += 3)
{
Vector3 p0 = m_ControlPointList[i].position;
Vector3 p1 = m_ControlPointList[i + 1].position;
Vector3 p2 = m_ControlPointList[i + 2].position;
Vector3 p3 = m_ControlPointList[i + 3].position;
for (int j = 0; j <= m_CurveDensity; j++)
{
float t = j * 1f / m_CurveDensity;
Vector3 point = BezierUtils.BezierCurve(p0, p1, p2, p3, t);
pointList.Add(point);
}
}
}
//绘制所有点
foreach (var point in pointList)
{
Gizmos.DrawSphere(point, 0.1f);
}
//绘制控制点连线
Gizmos.color = Color.red;
for (int i = 0; i < m_ControlPointList.Count - 1; i++)
{
Gizmos.DrawLine(m_ControlPointList[i].position, m_ControlPointList[i + 1].position);
}
}
}