1. 程式人生 > >Unity3d 簡單的小球沿貝塞爾曲線運動(適合場景漫遊使用)

Unity3d 簡單的小球沿貝塞爾曲線運動(適合場景漫遊使用)

轉載收藏:https://www.cnblogs.com/yanghui0702/p/yanghui20171122.html

簡單的小球沿貝塞爾曲線運動,適合場景漫遊使用

貝塞爾曲線:(貝塞爾曲線的基本想法部分摘自http://blog.csdn.net/u010019717/article/details/47684223 。僅供學習,知識分享。如有侵權,聯絡刪除。)

貝塞爾曲線是最基本的曲線,一般用在計算機 圖形學和 影象處理。貝塞爾曲線可以用來建立平滑的曲線的道路、 彎曲的路徑就像 祖瑪遊戲、 彎曲型的河流等。

        一條貝塞爾曲線是由一組定義的控制點 P0到 Pn,在 n 呼叫它的順序 (n = 1 為線性,2 為二次,等.)。第一個和最後一個控制點總是具有終結點的曲線;然而,中間兩個控制點 (如果有的話) 一般不會位於曲線上 。

貝塞爾曲線包含兩個控制點即 n = 2 稱為線性的貝塞爾曲線

貝塞爾曲線包含三個控制點即 n = 3 稱為二次貝塞爾曲線

貝塞爾曲線包含四個控制點即 n = 4,所以稱為三次貝塞爾曲線。

 

貝塞爾曲線返回點的貝塞爾函式,使用線性插值的概念作為基礎。所以,讓我們瞭解什麼首先是線性插值。

兩個點之間的線性插值的點獲取那兩個點之間,0 <= t <= 1,像 Mathf.Lerp 。

插值點,與 P 公式P0和 P1可以寫成,

P = P0+ t (P1 - P0),0 <= t <= 1

在這裡,為得到插值的點我們新增 tth指向 P 的分數與這兩個之間的距離0.所以,

For T = 0,P = P0.

For T = 1,P = P1.

For T = 0.5,P =  P0和 P1間的點.

 

線性的貝塞爾曲線:

線性的貝塞爾曲線有兩個控制點。為給出了兩個點 P0和 P1一個線性的貝塞爾曲線是隻是這兩個點之間的直線。曲線是相當於線性插值給出,

B(t) = P0+ t (P1 -  P0) = (1-t) P0 + tP1    ,0 <= t <= 1

        線性貝塞爾曲線如何計算出來的是如下所示:

 

 

 

二次貝塞爾曲線:

        二次貝塞爾曲線具有三個控制點。二次貝塞爾曲線是點對點的兩個線性貝塞爾曲線的線性插值。為給出了三個點 P0、P1和 P2一條二次貝塞爾曲線,其實是兩條線性的貝塞爾曲線,線性貝塞爾曲線的 P0和 P1和   線性貝塞爾曲線P1和 P2.     所以,給出二次貝塞爾曲線 :

B(t) = (1-t) BP0P1(t) + t BP1P2(t),0 <= t <= 1

B(t) = (1-t) [(1-t) P0 + tP1] + t [(1-t) P1+ tP2],0 <= t <= 1

 

通過重新排列上述方程,

B(t) = (1-t)2P0+ 2 (1-t) tP1 + t2P2,   0 <= t <= 1

二次貝塞爾曲線動畫計算如下所示:

 

 

三次貝塞爾曲線:

三次方貝塞爾曲線具有四個控制點。二次貝塞爾曲線是  點對點的兩條二次貝塞爾曲線的線性插值。對於給出的四個點 P0、P1、P2和 P3三次方貝塞爾曲線,是二次貝塞爾曲線P0、P1和 P2和   二次貝塞爾曲線P1、P2和 P3 得到的 線性插值  .所以,給出三次方貝塞爾曲線

B(t) = (1-t) BP0,P1,P2(t) + t BP1,P2,P3(t),0 <= t <= 1

B(t) = (1-t) [(1-t)2P0+ 2 (1-t) tP1 + t2P2] + t [(1-t)2P1+ 2 (1-t) tP2 + t2P3],0 <= t <= 1

 

通過重新排列上述方程中,

B(t) = (1-t)3P0 + 3(1-t)2tP1+ 3 (1-t) t2P2 + t3P3           0 <= t <= 1

三次貝塞爾曲線計算如下所示:

 

所以,一般可以作為點對點的線性插值獲得從兩個相應的貝賽爾曲線的程度 n-1 的兩個點定義程度 n 的貝塞爾曲線(就是高階的是兩個低一級的線性插值)。

以下是本人所寫。

Hierarchy檢視如下:

效果如下動畫所示:

 

指令碼如下:(指令碼掛載在場景中任意物件上)

複製程式碼
  1 using System.Collections;
  2 using System.Collections.Generic;
  3 using UnityEngine;
  4 
  5 //實現程式碼如下:(最外層有6個點,依次5,4,3,2,1)
  6 //新增一個小球,沿曲線運動,使小球看向目標物體
  7 public class Test_DrawLine : MonoBehaviour {
  8     
  9     [SerializeField] private Transform points;                          //控制點父物件
 10     private List<Transform> point_tranList = new List<Transform>();     //控制點列表
 11     [SerializeField] private int pointCount = 100;                      //曲線點的個數
 12     private List<Vector3> line_pointList;                               //曲線點列表
 13 
 14     [SerializeField] private Transform lookTarget;                      //看向目標
 15     [SerializeField] private GameObject ball;                           //運動物體
 16     [SerializeField] private float time0 = 0;                           //曲線點之間移動時間間隔
 17     private float timer = 0;                    //計時器
 18     private int item = 1;                       //曲線點的索引
 19     private bool isTrue = false;
 20 
 21     //使小球沿曲線運動
 22     //這裡不能直接在for裡以Point使用差值運算,看不到小球運算效果
 23     //定義一個計時器,在相隔時間內進行一次差值運算。
 24     void Awake()
 25     {
 26         Init();
 27     }
 28     void Init()
 29     {
 30         if (null != points && point_tranList.Count == 0)
 31         {
 32             foreach (Transform item in points)
 33             {
 34                 point_tranList.Add(item);
 35             }
 36         }
 37         line_pointList = new List<Vector3>();
 38         for (int i = 0; point_tranList.Count != 0 && i < pointCount; i++)
 39         {
 40             //
 41             Vector3 pos1 = Vector3.Lerp(point_tranList[0].position, point_tranList[1].position, i / (float)pointCount);
 42             Vector3 pos2 = Vector3.Lerp(point_tranList[1].position, point_tranList[2].position, i / (float)pointCount);
 43             Vector3 pos3 = Vector3.Lerp(point_tranList[2].position, point_tranList[3].position, i / (float)pointCount);
 44             Vector3 pos4 = Vector3.Lerp(point_tranList[3].position, point_tranList[4].position, i / (float)pointCount);
 45             Vector3 pos5 = Vector3.Lerp(point_tranList[4].position, point_tranList[5].position, i / (float)pointCount);
 46 
 47             //
 48             var pos1_0 = Vector3.Lerp(pos1, pos2, i / (float)pointCount);
 49             var pos1_1 = Vector3.Lerp(pos2, pos3, i / (float)pointCount);
 50             var pos1_2 = Vector3.Lerp(pos3, pos4, i / (float)pointCount);
 51             var pos1_3 = Vector3.Lerp(pos4, pos5, i / (float)pointCount);
 52             //
 53             var pos2_0 = Vector3.Lerp(pos1_0, pos1_1, i / (float)pointCount);
 54             var pos2_1 = Vector3.Lerp(pos1_1, pos1_2, i / (float)pointCount);
 55             var pos2_2 = Vector3.Lerp(pos1_2, pos1_3, i / (float)pointCount);
 56             //
 57             var pos3_0 = Vector3.Lerp(pos2_0, pos2_1, i / (float)pointCount);
 58             var pos3_1 = Vector3.Lerp(pos2_1, pos2_2, i / (float)pointCount);
 59             //
 60             Vector3 find = Vector3.Lerp(pos3_0, pos3_1, i / (float)pointCount);
 61 
 62             line_pointList.Add(find);
 63         }
 64         if (line_pointList.Count == pointCount)
 65             isTrue = true;
 66     }
 67 
 68     void Update()
 69     {
 70         if (!isTrue)
 71             return;
 72         timer += Time.deltaTime;
 73         if (timer > time0)
 74         {
 75             timer = 0;
 76             if(item >= line_pointList.Count-10)
 77             {
 78                 ball.transform.LookAt(line_pointList[item]);
 79             }
 80             else
 81             {
 82                 if (lookTarget)
 83                     ball.transform.LookAt(lookTarget);
 84                 else
 85                     ball.transform.LookAt(line_pointList[item]);
 86             }
 87             ball.transform.localPosition = Vector3.Lerp(line_pointList[item - 1], line_pointList[item], 1f);
 88             item++;
 89             if (item >= line_pointList.Count)
 90                 item = 1;
 91         }
 92     }
 93     
 94     //------------------------------------------------------------------------------
 95     //在scene檢視顯示
 96     void OnDrawGizmos()//畫線
 97     {
 98         Init();
 99         Gizmos.color = Color.yellow;
100         for (int i = 0; i < line_pointList.Count - 1; i++)
101         {
102             Gizmos.DrawLine(line_pointList[i], line_pointList[i + 1]);
103         }
104     }
105   
106 }
複製程式碼

 

好好把握每一次學習的機會,你會發現自己時刻在成長! 不想放棄夢想,所以一直堅持,雖無人鼓勵,但要活出自己!