Unity 中贝塞尔曲线的实现

 

一、简介

贝塞尔曲线是最基本的曲线,一般用在计算机 图形学和 图像处理。贝塞尔曲线可以用来创建平滑的曲线的道路、 弯曲的路径就像 祖玛游戏、 弯曲型的河流等。

        一条贝塞尔曲线是由一组定义的控制点 P0到 Pn,在 n 调用它的顺序 (n = 1 为线性,2 为二次,等.)。第一个和最后一个控制点总是具有终结点的曲线;然而,中间两个控制点 (如果有的话) 一般不会位于曲线上 。

  (1)贝塞尔曲线包含两个控制点即 n = 2 称为线性的贝塞尔曲线

  (2)贝塞尔曲线包含三个控制点即 n = 3 称为二次贝塞尔曲线

  (3)贝塞尔曲线包含四个控制点即 n = 4,所以称为三次贝塞尔曲线。

   贝塞尔曲线返回点的贝塞尔函数,使用线性插值的概念作为基础。

 

二、公式

1.线性贝塞尔公式:

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

其等同于线性插值。

效果图(文章中部分图片转载自CSDN):

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所决定的贝兹曲线。

TIPS:

通过两个低阶的贝塞尔曲线插值的堆叠总能够获得更高阶的贝塞尔曲线,通俗的来说通过对两条低阶的贝塞尔曲线插值,你可以求得一条高一阶的贝塞尔曲线。

比如:二次贝塞尔曲线是点对点的两个线性贝塞尔曲线的线性插值,三次贝塞尔曲线是两条二次贝塞尔曲线的线性插值。

三、实现与应用

效果图

通过拖动四个球可以实现不同的曲线。以上是三次贝塞尔曲线。

代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(LineRenderer))]
public class TripleBezier : MonoBehaviour {

    public Transform[] controlPoint;
    public LineRenderer lineRenderer;

    private int layerOrder = 0;
    //取样数
    private int _segmentNum = 5000;
	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, controlPoint[nodeIndex].position, controlPoint[nodeIndex + 1].position,
                    controlPoint[nodeIndex + 2].position, controlPoint[nodeIndex + 3].position);
                lineRenderer.positionCount = i;
                lineRenderer.SetPosition(i - 1, pixel);
            }
    }
    //获得贝塞尔曲线的数组
    Vector3 CalculateCubicBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2,Vector3 p3)
    {
        float u = 1 - t;
        float uu = u * u;
        float uuu = u * u * u;
        float tt = t * t;
        float ttt = t * t * t;
        Vector3 p = p0 * uuu;
        p += 3 * p1 * t * uu;
        p += 3 * p2 * tt * u;
        p += p3 * ttt;
        return p;

    }
}

二次贝塞尔曲线实现代码如下:

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 = 5000;


    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.positionCount = i;
            lineRenderer.SetPosition(i - 1, pixel);
        }

    }

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

}

二次贝塞尔工具类代码如下:

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

public class BezierUtils
{
    /// <summary>
    /// 根据T值,计算贝塞尔曲线上面相对应的点
    /// </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;

    }
}

以上参考自:http://www.cnblogs.com/msxh/p/6270468.html

补充:LineRenderer

画出不同颜色的线:

1.先添加一个材质。

2.再改颜色和alpha值。

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值