BezierCurve-Unity中創(chuàng)建貝塞爾曲線

Foreword

好記性不如爛筆頭。

BezierCurve簡介

在數(shù)學(xué)的數(shù)值分析領(lǐng)域中俩滥,貝塞爾曲線(英語:Bézier curve,亦作“貝塞爾”)是計(jì)算機(jī)圖形學(xué)中相當(dāng)重要的參數(shù)曲線错忱。更高維度的廣泛化貝塞爾曲線就稱作貝塞爾曲面航背,其中貝塞爾三角是一種特殊的實(shí)例棱貌。 —— 維基百科
婚脱。本篇只討論曲線。

構(gòu)建Bezier曲線

  • 線性曲線 由兩個(gè)頂點(diǎn)構(gòu)成错森。線性貝塞爾曲線函數(shù)中的t會(huì)經(jīng)過由P0至P1的B(t)所描述的曲線涩维。例如當(dāng)t=0.25時(shí),B(t)即一條由點(diǎn)P0至P1路徑的四分之一處蜗侈。就像由0至1的連續(xù)t踏幻,B(t)描述一條由P0至P1的直線戳杀。高階的曲線全部基于這個(gè)線性插值信卡。(Unity中向量的插值計(jì)算方法Vector3.Lerp可以完美實(shí)現(xiàn))
    線性貝塞爾曲線演示動(dòng)畫傍菇,t在[0,1]區(qū)間
  • 二次曲線 由三個(gè)點(diǎn)構(gòu)成。建構(gòu)二次貝塞爾曲線须妻,可以使中介點(diǎn)Q0和Q1作為由0至1的t:

    1. 由P0至P1的連續(xù)點(diǎn)Q0荒吏,描述一條線性貝塞爾曲線绰更。
    2. 由P1至P2的連續(xù)點(diǎn)Q1锡宋,描述一條線性貝塞爾曲線。
    3. 由Q0至Q1的連續(xù)點(diǎn)B(t)徐钠,描述一條二次貝塞爾曲線尝丐。
    二次貝塞爾曲線的結(jié)構(gòu)
    二次貝塞爾曲線演示動(dòng)畫爹袁,t在[0,1]區(qū)間
  • 高階曲線 建構(gòu)高階曲線失息,便需要相應(yīng)更多的中介點(diǎn)盹兢。

    1. 三次貝塞爾曲線
    三次貝塞爾曲線的結(jié)構(gòu)
    三次貝塞爾曲線演示動(dòng)畫蛤迎,t在[0,1]區(qū)間
    1. 四次貝塞爾曲線
    四次貝塞爾曲線的結(jié)構(gòu)
    四次貝塞爾曲線演示動(dòng)畫替裆,t在[0,1]區(qū)間
    1. 更高階同理辆童,需要更多的中介點(diǎn)把鉴,詳細(xì)見代碼塊儿咱。

應(yīng)用與代碼

二次貝塞爾曲線

//pointList 為頂點(diǎn)集合。 point1怠缸,point2揭北,point3 為構(gòu)建曲線的三個(gè)頂點(diǎn)

//Vector3.Lerp 為 UnityEngine 中的API吏颖。通過傳入兩點(diǎn)和之間的插值(0~1)得到一個(gè)新的三維向量

//vertexCount 為構(gòu)建曲線的頂點(diǎn)數(shù),此數(shù)值越大曲線越平滑

public static Vector3[] GetBezierCurveWithThreePoints(Vector3 point_1, Vector3 point_2, Vector3 point_3, int vertexCount)
{
    List<Vector3> pointList = new List<Vector3>();
    for (float ratio = 0; ratio <= 1; ratio += 1.0f / vertexCount)
    {
        //首先取前兩個(gè)點(diǎn)和后兩個(gè)點(diǎn)的線性插值疚俱。

        Vector3 tangentLineVertex1 = Vector3.Lerp(point_1, point_2, ratio);
        Vector3 tangentLineVertex2 = Vector3.Lerp(point_2, point_3, ratio);
        //通過計(jì)算兩個(gè)點(diǎn)的插值得到曲線的頂點(diǎn)

        Vector3 bezierPoint = Vector3.Lerp(tangentLineVertex1, tangentLineVertex2, ratio);
        pointList.Add(bezierPoint);
    }
    pointList.Add(point_3);
    return pointList.ToArray();
}

二次貝塞爾曲線unity中演示效果

二次貝塞爾曲線演示動(dòng)畫

高階貝塞爾曲線

//傳入頂點(diǎn)集合,得到高階的貝塞爾曲線瞧壮,頂點(diǎn)數(shù)量不限

//vertexCount 為構(gòu)建曲線的頂點(diǎn)數(shù),此數(shù)值越大曲線越平滑

public static Vector3[] GetBezierCurveWithUnlimitPoints(Vector3[] vertex, int vertexCount)
{
    List<Vector3> pointList = new List<Vector3>();
    pointList.Clear();
    for (float ratio = 0; ratio <= 1; ratio += 1.0f / vertexCount)
    {
        pointList.Add(UnlimitBezierCurve(vertex, ratio));
    }
    pointList.Add(vertex[vertex.Length - 1]);

    return pointList.ToArray();
}

public static Vector3 UnlimitBezierCurve(Vector3[] vecs, float t)
{
    Vector3[] temp = new Vector3[vecs.Length];
    for (int i = 0; i < temp.Length; i++)
    {
        temp[i] = vecs[i];
    }
    //頂點(diǎn)集合有多長陈轿,曲線的每一個(gè)點(diǎn)就需要計(jì)算多少次麦射。

    int n = temp.Length - 1;
    for (int i = 0; i < n; i++)
    {
        //依次計(jì)算各兩個(gè)相鄰的頂點(diǎn)的插值,并保存蛔琅,每次計(jì)算都會(huì)進(jìn)行降階罗售。剩余多少階計(jì)算多少次钩述。直到得到最后一條線性曲線。

        for (int j = 0; j < n - i; j++)
        {
            temp[j] = Vector3.Lerp(temp[j], temp[j + 1], t);
        }
    }
    //返回當(dāng)前比例下曲線的點(diǎn)
    return temp[0];
}

高階貝塞爾曲線unity中演示效果

高階貝塞爾曲線演示動(dòng)畫

整體腳本代碼

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

[ExecuteInEditMode]
public class BezierCurvePointRenderer : MonoBehaviour
{

    public Transform point1;
    public Transform point2;
    public Transform point3;
    public LineRenderer lineRenderer;
    public int vertexCount;

    public Transform[] positions;

    private List<Vector3> pointList;
    private void Start()
    {
        pointList = new List<Vector3>();
    }
    private void Update()
    {
        //BezierCurveWithThree();

        BezierCurveWithUnlimitPoints();

        lineRenderer.positionCount = pointList.Count;
        lineRenderer.SetPositions(pointList.ToArray());
    }

    private void BezierCurveWithThree()
    {
        pointList.Clear();
        for (float ratio = 0; ratio <= 1; ratio += 1.0f / vertexCount)
        {
            Vector3 tangentLineVertex1 = Vector3.Lerp(point1.position, point2.position, ratio);
            Vector3 tangentLineVertex2 = Vector3.Lerp(point2.position, point3.position, ratio);
            Vector3 bezierPoint = Vector3.Lerp(tangentLineVertex1, tangentLineVertex2, ratio);
            pointList.Add(bezierPoint);
        }
        pointList.Add(point3.position);
    }

    public void BezierCurveWithUnlimitPoints()
    {
        pointList.Clear();
        for (float ratio = 0; ratio <= 1; ratio += 1.0f / vertexCount)
        {
            pointList.Add(UnlimitBezierCurve(positions, ratio));
        }
        pointList.Add(positions[positions.Length - 1].position);
    }
    public Vector3 UnlimitBezierCurve(Transform[] trans, float t)
    {
        Vector3[] temp = new Vector3[trans.Length];
        for (int i = 0; i < temp.Length; i++)
        {
            temp[i] = trans[i].position;
        }
        int n = temp.Length - 1;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n - i; j++)
            {
                temp[j] = Vector3.Lerp(temp[j], temp[j + 1], t);
            }
        }
        return temp[0];
    }

    private void OnDrawGizmos()
    {


        #region 無限制頂點(diǎn)數(shù)

        Gizmos.color = Color.green;

        for (int i = 0; i < positions.Length - 1; i++)
        {
            Gizmos.DrawLine(positions[i].position, positions[i + 1].position);
        }

        Gizmos.color = Color.red;

        Vector3[] temp = new Vector3[positions.Length];
        for (int i = 0; i < temp.Length; i++)
        {
            temp[i] = positions[i].position;
        }
        int n = temp.Length - 1;
        for (float ratio = 0.5f / vertexCount; ratio < 1; ratio += 1.0f / vertexCount)
        {
            for (int i = 0; i < n - 2; i++)
            {
                Gizmos.DrawLine(Vector3.Lerp(temp[i], temp[i + 1], ratio), Vector3.Lerp(temp[i + 2], temp[i + 3], ratio));
            }

        }
        #endregion

        //#region 頂點(diǎn)數(shù)為3

        //Gizmos.color = Color.green;

        //Gizmos.DrawLine(point1.position, point2.position);

        //Gizmos.color = Color.green;

        //Gizmos.DrawLine(point2.position, point3.position);

        //Gizmos.color = Color.red;

        //for (float ratio = 0.5f / vertexCount; ratio < 1; ratio += 1.0f / vertexCount)
        //{

        //    Gizmos.DrawLine(Vector3.Lerp(point1.position, point2.position, ratio), Vector3.Lerp(point2.position, point3.position, ratio));

        //} 
        
        //#endregion
    }
}


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末放钦,一起剝皮案震驚了整個(gè)濱河市操禀,隨后出現(xiàn)的幾起案子蔚叨,更是在濱河造成了極大的恐慌蔑水,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丹擎,死亡現(xiàn)場離奇詭異歇父,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)护戳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門媳荒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抗悍,“玉大人缴渊,你說我怎么就攤上這事鱼炒。” “怎么了指蚁?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵欣舵,是天一觀的道長缀磕。 經(jīng)常有香客問我劣光,道長,這世上最難降的妖魔是什么绢涡? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任雄可,我火速辦了婚禮,結(jié)果婚禮上聪舒,老公的妹妹穿的比我還像新娘虐急。我一直安慰自己,他們只是感情好被辑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布盼理。 她就那樣靜靜地躺著俄删,像睡著了一般勾哩。 火紅的嫁衣襯著肌膚如雪举哟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天潜叛,我揣著相機(jī)與錄音威兜,去河邊找鬼庐椒。 笑死,一個(gè)胖子當(dāng)著我的面吹牛笔宿,可吹牛的內(nèi)容都是我干的棱诱。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼炬灭,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼重归!你這毒婦竟也來了厦凤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤狈网,失蹤者是張志新(化名)和其女友劉穎笨腥,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體士鸥,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡烤礁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了脚仔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡们颜,死狀恐怖猎醇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情阻问,我是刑警寧澤称近,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布曹鸠,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏晾蜘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一肆饶、第九天 我趴在偏房一處隱蔽的房頂上張望驯镊。 院中可真熱鬧竭鞍,春花似錦、人聲如沸冯乘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翔横。三九已至棕孙,卻和暖如春些膨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背订雾。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國打工洼哎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人锭沟。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓族淮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親凭涂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子切油,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容