BooheeFE / weekly

📝 薄荷前端周刊 Boohee Front End Team Weekly
762 stars 40 forks source link

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

Open wieve opened 5 years ago

wieve commented 5 years ago

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

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

贝塞尔曲线原理

贝塞尔曲线由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 ★,转载请注明出处。

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