如何理解並應用貝塞爾曲線

薄荷前端發表於2019-03-14

貝塞爾曲線又叫貝茲曲線,在大學高數中一度讓我非常頭疼。前陣子練手寫動畫的時候,發現貝塞爾曲線可以應用於軌跡的繪製以及定義動畫曲線。

本文就來探究一下,貝塞爾曲線到底是個什麼樣的存在。

貝塞爾曲線原理

貝塞爾曲線由n個點來決定,其曲線軌跡可以由一個公式來得出:

貝塞爾公式

其中n就代表了貝塞爾曲線是幾階曲線,該公式描述了曲線運動的路徑。

以下我們來討論一下,貝塞爾公式如何推導。

一階貝塞爾曲線

一階

設定圖中運動的點為Pt,t為運動時間,t∈(0,1),可得如下公式

公式1

二階貝塞爾曲線

二階

二階座標

在二階貝塞爾曲線中,已知三點恆定(P0,P1,P2),設定在P0P1中的點為Pa,在P1P2中的點為Pb,Pt在PaPb上的點,這三點都在相同時間t內做勻速運動。

由公式(1)可知

公式2

將公式(2)(3)代入公式(4)中,可得

公式3

三階貝塞爾曲線

三階

三階座標

同理,根據以上的推導過程可得

公式4

由此可以推導

公式5

n階貝塞爾曲線

四階

五階

放上一個網址,隨意感受一下貝塞爾曲線的繪製過程:

myst729.github.io/bezier-curv…

實際應用

貝塞爾曲線在前端中主要有兩方面的應用,一方面可以作為動畫曲線應用於CSS3動畫中;另一方面可以通過canvas來繪製曲線達到需要的效果。

CSS3中貝塞爾曲線的應用

在CSS3中,有兩屬性經常被用到:transition-timing-functionanimation-timing-function,這兩個分別代表了過渡的速度和動畫的速度。CSS3為我們提供了一個新的工具——cubic-bezier(x1,y1,x2,y2)。這個工具能夠生成一個速度曲線,使我們的元素按照該曲線來調節速度。

在上面的推導中,我們知道在貝塞爾公式中,有兩個點的位置恆定——P0和P1,cubic-bezier中定義了兩個控制點的位置,所以該曲線為三階貝塞爾曲線。

有個網站可以方便我們快速建立一個貝塞爾曲線:cubic-bezier

貝塞爾曲線與動畫曲線的關聯

先來一波動圖簡單粗暴的感受一下: 例一:

1

例二:

2

例三:

3

左邊的是貝塞爾曲線,橫軸代表了事件,豎軸代表了進度,無法直觀得感受出速度的變化。

右邊的曲線是控制皮膚中的動畫曲線,橫軸是時間,豎軸是速度,可以方面地看出速度的變化。

上述例子中,以前進反向為速度正方向,後退方向為速度反方向。

如何得知速度的變化

推導

例一中,貝塞爾曲線為一條直線,當時間均勻變化時,進度也在均勻變大,由此可知速度恆定不變,時間和進度之間的關係可以用一個線性方程來表示:

y=ax+b (a=1,b=0)
複製程式碼

其中x為時間,y為進度,a即為速度。

推導案例一

從上面結論中啟發,去觀察其他貝塞爾曲線,

方程一

圖中是一段變化的曲線,我們取其中一小段,將其看作穩定不變的一段直線,通過下面的線性方程來表示,並通過紅線標註在圖中:

y=ax+b
複製程式碼

根據初中數學的內容,我們知道,當a>1時,與x軸的夾角∈(45°,90°);當a∈(0,1)時,與x軸的夾角在(0,45°)之間。相同的時間內,與x軸的夾角越大,a越大,速度越快。

觀察上圖的夾角變化趨勢,夾角逐漸變小趨向於0,而後逐漸變大,趨向於90°,對應速度應是速度逐漸變慢趨向於0,之後逐漸變快。

放上動畫曲線以及動圖來驗證一下我們的推測:

方程一(1)

5

推導案例二

下圖中的曲線部分在第四象限,部分在第一象限,這時對應的動畫曲線該如何推導呢。

同樣將該曲線視為由n段平滑的直線構成,由線性方程來表示直線的趨勢,可知速度a方向一開始為負,之後慢慢向正方靠近,a的速率也在由大變小,當為0時,再向正方慢慢變大。即該曲線表示元素一開始在朝反方向減速運動,當速度為0後,向正方向作加速運動。

方程三

通過動畫曲線及動圖來驗證上述推導:

方程三(1)

6

驗證

用兩個曲線來驗證一下上面的結論:

曲線一:

方程二

方程二(1)

3

曲線二:

方程四

方程四(1)

7

從結果可以判斷,用上述推導方法可以正確得出貝塞爾曲線與動畫曲線之間的關係。

動畫曲線的應用

瞭解瞭如何用貝塞爾曲線來指定動畫曲線後,很多動畫涉及到速度方面的效果就可以實現了,例如小車加速剎車,彈簧動畫等速度軌跡都可以根據自己的需要來進行定製。

放上一個緩動函式速查網址,可以讓自己的動效更加真實:緩動函式

放一個小例子:

動畫案例

該動畫模擬了小球落下回彈的過程

程式碼如下:

    <div class="ground">
      <div class="ball" id="ball"></div>
    </div>
複製程式碼
      .ball {
        width: 30px;
        height: 30px;
        background: #000000;
        border-radius: 50%;
        position: absolute;
        top: 0;
        left: 50%;
        animation: move 4s cubic-bezier(0.36, 1.7, 0.26, 0.61) 1s infinite;
      }

      @keyframes move {
        0% {
          top: 0;
        }
        100% {
          top: 90%;
        }
      }
複製程式碼

這類動畫可以參考網上大大們的案例:

貝塞爾曲線與CSS3動畫、SVG和canvas的應用

理解與運用貝塞爾曲線

利用canvas繪製貝塞爾曲線

canvas中提供了api可以快速繪製一條貝塞爾曲線,來達到需要的效果:

二階貝塞爾曲線

quadraticCurveTo(x1,y1,x2,y2)

var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.moveTo(20,20);
ctx.quadraticCurveTo(40,200,200,20);
ctx.stroke();
複製程式碼

canvas-2階

其中moveTo定義了起始點,quadraticCurveTo(x1,y1,x2,y2)中的(x1,y1)為控制點,(x2,y2)為終點

三階貝塞爾曲線

bezierCurveTo(x1,y1,x2,y2,x3,y3)

var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.moveTo(20,20);
ctx.bezierCurveTo(40,100,200,150,200,20);
ctx.stroke();
複製程式碼

canvas-3階

其中moveTo定義了起始點,bezierCurveTo(x1,y1,x2,y2)中的(x1,y1),(x2,y2)為控制點,(x3,y3)為終點

總結

為了弄清貝塞爾曲線是個什麼東西,和動畫曲線、速度又有什麼關聯,作者跑去複習了一下那些早扔給老師的東西,有說錯的請輕拍/(ㄒoㄒ)/~~

廣而告之

本文釋出於薄荷前端週刊,歡迎Watch & Star ★,轉載請註明出處。

歡迎討論,點個贊再走吧 。◕‿◕。 ~

我的部落格即將同步至騰訊雲+社群,邀請大家一同入駐:cloud.tencent.com/developer/s…

相關文章