只要有適當的數學公式,就可以算出每個點的位置然後繪製圖形,〈黃金螺線〉 中看過的螺線繪製就是實際的例子,你可以在 Wolfram Alpha 知識引擎中,搜尋「Doraemon‐like curve」,這可以找到曲線繪製出的哆啦 A 夢,以及曲線的參數式:
你可以試著搜尋 xxx curve,例如「person curve」等,來試著找到其他有趣的曲線;然而有時候,我們數學不夠好或者嫌麻煩,難以或不想找出數學公式來表現想要的曲線,怎麼辦呢?
這時,可以使用〈貝茲曲線〉來近似出想要的曲線,在各種近似曲線中,貝茲曲線的數學原理算是蠻好懂的,認識一下,有助於掌握貝茲曲線或其他近似曲線的運用方式。
如果對微積分還有些印象,大概會記得曲線的微分,可以用來求某點的切線斜率,如果忘了,可以這麼想,如果每次只看曲線中的一小段,那麼這一小段 曲線只要夠短,小到趨近於 0 的極限,那麼幾乎就可以看成是一段直線:
更具體地說,如果曲線的函數是 f(x),而曲線上有某點 (x, y),若於 X 方向前進 Δx 距離,會得到 Δy = f(x + Δx) - f(x),剛才說 到一小段曲線只要夠短的意思是,若 Δx 趨近於 0,這時這一小段曲線變化就可以看成是直線,而直線的斜率是 Δy / Δx(這段描述其實就是微分的定義,而這一小段直線,就是曲線在點 (x, y) 處的切線)。
從這個觀點來看,一段曲線,可以看成是無數的直線構成(這就是積分的概念),只不過,上一個點跟下一個點的直線斜率也許不相同:
如果有曲線的函數 f(x),其微分 f'(x) 代入每個點的 (x, y) 就可以得到通過這個點的直線斜率,從而得到通過這個點的直線方程式,問題就在於剛剛談到的,有時候,我們數學不夠好或者嫌麻煩,難以或不想找出數學公式 f(x) 來表現想要的曲線,怎麼辦呢?
貝茲曲線的概念就是,直接用直線來描述曲線,這是什麼意思?以二次貝茲曲線舉例來說,可以使用三個點 P0、P1、P2,在 P0 與 P1 間直線的四分之一處找個點 Q0,在 P1 與 P2 間直線的四分之一處找個點 Q1,這時 Q0 與 Q1 會構成一條直線,這時也在 Q0 與 Q1 之間直線的四分之一處找個點 B0。
接著類似的作法,只是將四分之一變成二分之一、四分之三,分別找出 B1、B2 好了,接著將 P0、B0、B1、B2、P2 連起來會是什麼呢?
有點像是曲線了,上面的例子其實就是將直線分為四等分,每次前進四分之一求 B 點,如果四變成了八、十六等更大的數,數字越大就越接近真正曲線了(這也是積分的概念)。
那麼要怎麼得到 Q0 與 Q1 這條直線?這得先從線性貝茲曲線開始談,也就是…直線!如果 P0 與 P1 之間的距離為 LEN, 從 P0 到 P1 的中間若前進了長度為 len,若 t = len / LEN, 那麼 B(t) 會是:
其中 P0、P1、B(t) 都是向量的意思,以 OpenSCAD 具體來說,如果以 [x, y, z] 這個向量來表示座標點的話,那麼點 P0 的座標 (x0, y0, z0) 可以用 [x0, y0, z0] 向量來表示,也就是若用矩陣來表示的話:
自行導證出這個公式很簡單,不想導證的話也沒關係,日後有興趣再導就好,總之接著來看,如果有三個點 P0、P1、P2 呢?若 P0 與 P1 間的點有個點 X0,P1 與 P2 間有個點 X1,如果 X0 與 X1 之間的距離為 LEN,從 X0 到 X1 的中間若前進了長度為 len,若 t = len / LEN,那 麼在上頭的某點 B 就會是:
B(t) = (1 - t) X0 + t X1, t ∈ [0, 1]
如果 X0 實際上是從 P0 前進到 P1 得到,那麼 X0 的位置可以表示為 X0(t):
X0(t) = (1 - t) P0 + t P1, t ∈ [0, 1]
如果 X1 實際上是從 P1 前進到 P2 得到,那麼 X1 的位置可以表示為 X1(t):
X1(t) = (1 - t) P1 + t P2, t ∈ [0, 1]
將 X0(t)、X1(t) 代入方才的 B(t),整理一下就會得到:
B(t) = (1 - t) * (1 - t) * P0 + 2 * t * (1 - t) * P1 + t * t * P2, t ∈ [0, 1]
這就是二次貝茲曲線的公式了,依同樣的邏輯,你可以求出三次或更多次的貝茲曲線,公式就直接看維基百科上的吧!(可以運用〈巴斯卡三角形〉來協助記憶!)
雖然可以實作更多次的貝茲曲線,不過控制點太多,實際上也不好控制曲線,因此最常使用的是三次貝茲曲線,也就是使用四個控制點…因此接下來就可以實作貝茲曲線了…等一下…
p5.js 就有內建貝茲曲線了,以最簡單的 bezier
為例,它實現了三次貝茲曲線,可以接受四個點,來繪製貝茲曲線,例如以下的例子,可以藉由滑鼠點選控制點,來改變曲線的形狀:
bezier
預設會將曲線切為 20 等分,這可以透過 bezierDetail
來控制(必須在 WebGL 模式);如果想取得曲線上計算出來的每個點的 x 或 y 座標,可以透過 bezierPoint
;還可以透過 bezierTangent
取得曲線上每個點的切線斜率的 x 分量或 y 分量,例如,可以透過以下程式來顯示曲線更多的細節: