Unity中的数学基础——贝塞尔曲线

文章介绍了贝塞尔曲线的基本概念,包括线性、二次和三次方程形式,以及如何在Unity中使用C#代码实现不同阶数的贝塞尔曲线,并展示了如何根据控制点密度绘制曲线。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:前言 

一条贝塞尔曲线是由一组定义的控制点P0到 Pn,n=1为线性,n=2为二次......第一个和最后一个控制点称为起点和终点,中间的控制点一般不会位于曲线上 
获取两个点之间的点就是通过线性插值( Mathf.Lerp),0 <= t <= 1


二:贝塞尔曲线公式

——线性公式:给定点P0、P1,线性贝兹曲线只是一条两点之间的直线。这条线由下式给出

1


——二阶贝塞尔曲线:二次方贝塞尔曲线的路径由给定点P0、P1、P2的函数B(t)公式推导:由(P0,P1),(P1,P2)分别求线性公式所得的结果P0‘ 和 P1‘再带入线性公式,整理所得即为二次公式
P0,P1所求:
1.1.1
P1,P2所求:
1.2.2
P0,P1,P2二次方公式:
1.2.3
简化所得
1.2.4


——三阶贝塞尔曲线:P0、P1、P2、P3四个点在平面或在三维空间中定义了三次方贝兹曲线。曲线起始于P0走向P1,并从P2的方向来到P3。一般不会经过P1或P2;这两个点只是在那里提供方向。P0和P1之间的间距,决定了曲线在转而趋进P3之前,走向P2方向的“长度有多长”。
其公式为
1.3.1 


三:公式转换为代码

using UnityEngine;
using System.Collections.Generic;

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

    /// <summary>
    /// n阶贝塞尔曲线
    /// </summary>
    public static Vector3 BezierCurve(List<Vector3> pointList, float t)
    {
        Vector3 B = Vector3.zero;
        if (pointList == null)
        {
            return B;
        }
        if (pointList.Count < 2)
        {
            return pointList[0];
        }

        List<Vector3> tempPointList = new List<Vector3>();
        for (int i = 0; i < pointList.Count - 1; i++)
        {
            Vector3 tempPoint = BezierCurve(pointList[i], pointList[i + 1], t);
            tempPointList.Add(tempPoint);
        }
        return BezierCurve(tempPointList, t);
    }
}

 四:绘制出曲线

  

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hello Bug.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值