寫在前面
最近給項目做了個路徑編輯,基本思路是滿足幾個基本需求:
【額外說明】其實本篇和這個沒關係,可以跳過“寫在前面”這部分,跨到正文部分
編輯時:
① 隨意增減、插入、刪除路點,只要路點數量大於1,繪製曲線,曲線必定經過路點。
② 調整路點的Forward方向,控制曲線的入線切線方向、出線切線方向。這樣可以通過旋轉直接調整曲線形狀。
③ 控制Forward方向的基礎上,增添描述切線“強度”的變量,來進一步控制曲線的形狀。
④ 可以指定每段曲線的邏輯長度,程序提供一個曲線近似長度幫助確定邏輯長度。
⑤ 導出曲線的數據。
運行時,可以根絕數據:
⑥ 對路點進行從0開始的編號,使用0.01~0.99來描述在某段曲線上的位置(邏輯上的),然後轉化成爲實際的座標。
⑦ 可以獲得在曲線上任意一點的切線方向。
正文
從路點、路點forward到三階貝塞爾曲線的四個點
每兩個路點作爲三階貝塞爾曲線的起點(第0個點P0)和終點(第3個點P3)。
起點路點的Forward方向乘以“強度”的變量,再加上起點座標,作爲第1個點P1。
起點路點的Forward反方向乘以“強度”的變量,再加上起點座標,作爲第2個點P2。
得到 p0~p4這四個點之後,即可使用三階貝塞爾曲線的相關公式了
繪製貝塞爾曲線,圖中紅色線條部分
三階貝塞爾曲線線上某點座標(Unity & C#)
三階貝塞爾曲線公式(來自百度百科)
形參中的 t, p0, p1, p2, p3 分別對應公式中的 t 以及 p0~p3
public Vector3 BezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
{
float u = 1 - t;
float tt = t * t;
float uu = u * u;
float uuu = uu * u;
float ttt = tt * t;
Vector3 p = uuu * p0;
p += 3 * uu * t * p1;
p += 3 * u * tt * p2;
p += ttt * p3;
return p;
}
三階貝塞爾曲線的近似長度(Unity & C#)
計算長度的思路:
在貝塞爾曲線上取n個點,計算點之間的直線長度,進行加和,從而取得一個曲線的近似長度。取點越多這個長度越趨向於精確。
形參中的p0, p1, p2, p3 分別對應公式中的 p0~p3。pointCount代表取點個數,默認30。
public float BezierLength(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, int pointCount = 30)
{
if (pointCount < 2)
{
return 0;
}
//取點 默認 30個
float length = 0.0f;
Vector3 lastPoint = BezierPoint(0.0f / (float)pointCount, p0, p1, p2, p3);
for (int i = 1; i <= pointCount; i++)
{
Vector3 point = BezierPoint((float)i/(float)pointCount, p0, p1, p2, p3);
length += Vector3.Distance(point, lastPoint);
lastPoint = point;
}
return length;
}
三階貝塞爾曲線線上某點的切線(Unity & C#)
在已知貝塞爾曲線表達式的情況下,想要知道某點的切線,對曲線求導。
可得:
整理後可得
整體公式構成只有p0~p3 以及 t 和 (1-t),爲了表達式更直接,不進行進一步的整理。
所以得到下面的代碼
形參中的 t, p0, p1, p2, p3 分別對應公式中的 t 以及 p0~p3
public Vector3 BezierTangent(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
{
float u = 1 - t;
float uu = u * u;
float tu = t * u;
float tt = t * t;
Vector3 P = p0 * 3 * uu * (-1.0f);
P += p1 * 3 * (uu - 2 * tu);
P += p2 * 3 * (2 * tu - tt);
P += p3 * 3 * tt;
//返回單位向量
return P.normalized;
}
寫在後面
主要參照:
Unity遊戲中使用貝塞爾曲線
求二次、三次貝塞爾曲線的某個時間的位置及切線方向
轉載請註明,出自喵喵丸的博客 (http://blog.csdn.net/u011643833/article/details/78540554)