setchi’s blog

コードに埋もれてます。

【Unity】ベジェ曲線を学び、実装する

ベジェ曲線とは

数式で曲線を表現する方法の一つです。
コンピュータ上で滑らかな曲線を表現できるため、多くのドローソフトや文字の描画で採用されています。

ベジェ曲線の原理

ベジェ曲線を理解するには、1次ベジェ曲線から一つずつ次元を上げながら動きを見ていくのが分かりやすいと思います。

1次ベジェ曲線

f:id:setchi_q:20170408000330g:plain*1
一本の線分(P0 から P1)の上を一定の割合で動く点を考えます。この点が動く軌跡が1次ベジェ曲線です。
つまり、ただの直線です。しかし、この動きがすべての基本になります。

「t」は線分上をどれだけの割合進んだのかを表す数値です。

2次ベジェ曲線

f:id:setchi_q:20170408000745g:plain*2
2次ベジェ曲線は、線分が一本増えて二本の線分(P0 から P1 と、P1 から P2)から成り立ちます。

1次ベジェ曲線と同じように、それぞれの線分上を一定の割合で動く点(緑色の点)を考えます。
その点同士を結ぶと、なめらかに動く一本の線分(緑色の線分)が出来上がります。

さらに、緑色の線分上を一定の割合で動く点(黒い点)をまた考えることができます。この点が動く軌跡が2次ベジェ曲線です。

3次ベジェ曲線

f:id:setchi_q:20170408001500g:plain*3
3次ベジェ曲線はさらに線分が一本増えて、三本の線分(P0 から P1、P1 から P2、P2 から P3)から成り立ちます。

1次ベジェ曲線と同じように、それぞれの線分上を一定の割合で動く点(緑色の点)を考えます。
その点同士を結ぶと、なめらかに動く二本の線分(緑色の線分)が出来上がります。

二本の緑色の線分に注目します。それぞれの線分上を一定の割合で動く点(青色の点)をまた考えることができます。
その点同士を結ぶと、なめらかに動く一本の線分(青色の線分)が出来上がります。

青色の線分に注目します。青色の線分上を一定の割合で動く点(黒い点)をまた考えることができます。この点が動く軌跡が3次ベジェ曲線です。

実装

今回は3次ベジェ曲線を実装しました。
UnityEngine.Vector3 には、ベクトルの線形補間を行う Lerp メソッドが用意されています。
Lerp メソッドを使って素直に実装すると下記のようになります。

Vector3 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
{
    var a = Vector3.Lerp(p0, p1, t); // 緑色の点1
    var b = Vector3.Lerp(p1, p2, t); // 緑色の点2
    var c = Vector3.Lerp(p2, p3, t); // 緑色の点3

    var d = Vector3.Lerp(a, b, t);   // 青色の点1
    var e = Vector3.Lerp(b, c, t);   // 青色の点2

    return Vector3.Lerp(d, e, t);    // 黒色の点
}

これでも動きますが、数学的には下記のように最適化できます。

Vector3 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
{
    var oneMinusT = 1f - t;
    return oneMinusT * oneMinusT * oneMinusT * p0 +
           3f * oneMinusT * oneMinusT * t * p1 +
           3f * oneMinusT * t * t * p2 +
           t * t * t * p3;
}

この関数を使って、Illustratorのペンツール風(?)に曲線を描いていけるGUIを実装しました。
github.com


f:id:setchi_q:20170408170518p:plain

まだ最低限の機能のみですが、機会を見つけたら実装練習も兼ねてリッチにしていきます。