一、简介
贝塞尔曲线是最基本的曲线,一般用在计算机 图形学和 图像处理。贝塞尔曲线可以用来创建平滑的曲线的道路、 弯曲的路径就像 祖玛游戏、 弯曲型的河流等。
一条贝塞尔曲线是由一组定义的控制点 P0到 Pn,在 n 调用它的顺序 (n = 1 为线性,2 为二次,等.)。第一个和最后一个控制点总是具有终结点的曲线。然而,中间两个控制点 (如果有的话) 一般不会位于曲线上 。
(1)贝塞尔曲线包含两个控制点即 n = 2 称为线性的贝塞尔曲线
(2)贝塞尔曲线包含三个控制点即 n = 3 称为二次贝塞尔曲线
(3)贝塞尔曲线包含四个控制点即 n = 4,所以称为三次贝塞尔曲线。
贝塞尔曲线返回点的贝塞尔函数,使用线性插值的概念作为基础。
二、公式
1.线性贝塞尔公式:(其等同于线性插值)
给定点P0、P1,线性贝兹曲线只是一条两点之间的直线。这条线由下式给出:
效果图(文章中部分图片转载自优快云):
2.二次贝塞尔公式:
二次方贝兹曲线的路径由给定点P0、P1、P2控制,这条线由下式给出:
效果图:
3.三次贝塞尔方程:
P0、P1、P2、P3四个点在平面或在三维空间中定义了三次方贝兹曲线。曲线起始于P0走向P1,并从P2的方向来到P3。一般不会经过P1或P2;这两个点只是用来充当控制点。P0和P1之间的间距,决定了曲线在转而趋进P3之前,走向P2方向的“长度有多长”。
曲线的参数形式为:
效果图:
4.一般参数形式的贝塞尔方程:
N阶贝兹曲线可如下推断。给定点P0、P1、…、Pn,其贝兹曲线即:
如上公式可如下递归表达: 用表示由点P0、P1、…、Pn所决定的贝兹曲线。
PS:二次贝塞尔曲线是点对点的两个线性贝塞尔曲线的线性插值,三次贝塞尔曲线是两条二次贝塞尔曲线的线性插值。
三、实现与应用
效果图:
通过调节起始点(左边的白球)、控制点(中间的白球)和结束点(右边的白球)可以获得到不同的贝塞尔曲线,然后使用LineRender组件将路径绘制出来,以方便观察。下面就是实现此功能的代码:
using UnityEngine;
using System.Collections.Generic;
[RequireComponent(typeof(LineRenderer))]
public class Bezier : MonoBehaviour
{
public Transform[] controlPoints;
public LineRenderer lineRenderer;
private int layerOrder = 0;
private int _segmentNum = 50;
void Start()
{
if (!lineRenderer)
{
lineRenderer = GetComponent<LineRenderer>();
}
lineRenderer.sortingLayerID = layerOrder;
}
void Update()
{
DrawCurve();
}
void DrawCurve()
{
for (int i = 1; i <= _segmentNum; i++)
{
float t = i / (float)_segmentNum;
int nodeIndex = 0;
Vector3 pixel = CalculateCubicBezierPoint(t, controlPoints[nodeIndex].position,
controlPoints[nodeIndex+1].position, controlPoints[nodeIndex+2].position);
lineRenderer.numPositions = i;
lineRenderer.SetPosition(i - 1, pixel);
}
}
//二次贝塞尔公式:B(t) = (1-t)²P。+ 2t(1-t)P₁ + t²P₂,t∈[0,1]
Vector3 CalculateCubicBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2)
{
float u = 1 - t;
float tt = t * t;
float uu = u * u;
Vector3 p = uu * p0;
p += 2 * u * t * p1;
p += tt * p2;
return p;
}
}
CalculateCubicBezierPoint()函数负责根据T值计算出对应的贝塞尔曲线中的点,DrawCurve()函数通过不断的改变T值,并调用CalculateCubicBezierPoint()获得坐标点,然后通过LineRenderer将这些点绘制出来。
为了使用方便,可以将计算贝赛尔曲线的方法放到一个工具类中——BezierUtils类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BezierUtils
{
/// <summary>
/// 根据T值,计算贝塞尔曲线上面相对应的点
/// 二次贝塞尔公式:B(t) = (1-t)²P。+ 2t(1-t)P₁ + t²P₂,t∈[0,1]
/// </summary>
/// <param name="t"></param>T值
/// <param name="p0"></param>起始点
/// <param name="p1"></param>控制点
/// <param name="p2"></param>目标点
/// <returns></returns>根据T值计算出来的贝赛尔曲线点
private static Vector3 CalculateCubicBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2)
{
float u = 1 - t;
float tt = t * t;
float uu = u * u;
Vector3 p = uu * p0;
p += 2 * u * t * p1;
p += tt * p2;
return p;
}
/// <summary>
/// 获取存储贝塞尔曲线点的数组
/// </summary>
/// <param name="startPoint"></param>起始点
/// <param name="controlPoint"></param>控制点
/// <param name="endPoint"></param>目标点
/// <param name="segmentNum"></param>采样点的数量
/// <returns></returns>存储贝塞尔曲线点的数组
public static Vector3 [] GetBeizerList(Vector3 startPoint, Vector3 controlPoint, Vector3 endPoint,int segmentNum)
{
Vector3 [] path = new Vector3[segmentNum];
for (int i = 1; i <= segmentNum; i++)
{
float t = i / (float)segmentNum;
Vector3 pixel = CalculateCubicBezierPoint(t, startPoint,
controlPoint, endPoint);
path[i - 1] = pixel;
Debug.Log(path[i-1]);
}
return path;
}
}
通过调用 GetBeizerList( )方法就可以获得到一个包含着计算出的贝塞尔曲线的数组,然后让Obejct沿着数组里面的路径移动就可以模拟出各种曲线运动的效果了,比如炮弹的飞行轨迹,香蕉球、弧圈球等等各种各样的曲线效果了,比如下面的效果图:
博客中贝塞尔曲线工程的开源地址:https://github.com/XINCGer/Unity3DTraining/tree/master/BezierTest
作者:马三小伙儿
出处:http://www.cnblogs.com/msxh/p/6270468.html
请尊重别人的劳动成果,让分享成为一种美德,欢迎转载。另外,文章在表述和代码方面如有不妥之处,欢迎批评指正。留下你的脚印,欢迎评论!