1. 程式人生 > >Unity__如何在遊戲中體現貝塞爾曲線

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所決定的貝茲曲線。

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 
請尊重別人的勞動成果,讓分享成為一種美德,歡迎轉載。另外,文章在表述和程式碼方面如有不妥之處,歡迎批評指正。留下你的腳印,歡迎評論!