Skip to content

2019/03/14 - 如何理解并应用贝塞尔曲线 #31

Description

@wieve

贝塞尔曲线又叫贝兹曲线,在大学高数中一度让我非常头疼。前阵子练手写动画的时候,发现贝塞尔曲线可以应用于轨迹的绘制以及定义动画曲线。

本文就来探究一下,贝塞尔曲线到底是个什么样的存在。

贝塞尔曲线原理

贝塞尔曲线由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阶贝塞尔曲线

四阶

五阶

放上一个网址,随意感受一下贝塞尔曲线的绘制过程:

http://myst729.github.io/bezier-curve/

实际应用

贝塞尔曲线在前端中主要有两方面的应用,一方面可以作为动画曲线应用于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 ★,转载请注明出处。

欢迎讨论,点个赞再走吧 。◕‿◕。 ~

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions