贝塞尔曲线真的有那么丝滑吗?用事实来一探究竟

1,061 阅读9分钟

前言

很多热爱设计开发的小伙伴,包括老叁我自己平时在学习绘图、后期剪辑、网页设计、建模等等时,都会遇到 “平滑过渡” 或者说是 “贝塞尔曲线” 的字眼。比如,这些地方都出现过它的身影:

  • PS 里的钢笔工具(不仅仅这里,大多数Adobe家的软件都有)
  • PR 里的缓入缓出关键帧以及插值调整贝塞尔曲线
  • H5+CSS3 制作的按钮效果
    由以上的案例可见,贝塞尔曲线在任何一款软件中,几乎都是一样的设计安排,其表现形式就是一条带有句柄和节点的 可调节的曲线。刚接触贝塞尔曲线的时候,我仅仅认为它就是一个简单的函数应用,即便不懂原理也可以瞎捣鼓一番,但是最后,在看到自己的作品和大神的之间那条鸿沟时,方才明白,厉害的事物往往设计简约,而内涵实在不简单!所以才想到要探究一下:贝塞尔曲线是什么,又怎么用,效果真的有那么丝滑吗?话不多说,接下来一起来看看吧。

本文讲述结构

主题

什么是贝塞尔曲线

概述

贝塞尔曲线(Bezier curve)是应用于二维图形应用程序的参数曲线,由“线段”和节点组成,节点是可拖动的支点,表示曲线的趋向,“线段”像可伸缩的橡皮筋。它抽象了线段和曲线,通过控制路径上的四个点(起始点、终止点、两个中间点)来编辑图形;其中中间点和端点的连线称为控制线,这是一条虚拟的线段;两端的端点用来改变曲线的曲率;移动中间点来改变曲线运动轨迹。

由来

贝塞尔曲线最初于1959年开发,由法国攻城狮 Pierre Bezier 在1962年间广泛发表,他起初是应用于汽车主体设计的,然而贝塞尔曲线在另外的领域发展如火如荼,甚至为计算机矢量图形学奠定了基础。大家都知道用电脑绘图不是一件容易的事情,用鼠标来绘制平滑的曲线更是难以操作,鼠绘与手绘的感觉也存在很大差异。所以在一开始,使用电脑制图并不像今天这样有着众多软件、硬件的辅助,那时候实在无法做到随心所欲。而贝塞尔工具的发明很大程度上改善了计算机绘图的僵硬方式。

参数函数定义与原理

一般(n阶)参数公式: 给定点,其贝塞尔曲线为:B(t)=\sum_{i=0}^{n}\binom{n}{i}P_{i}(1-t)^{n-i}t_{i},t\in [0,1] 特别的,线性(一阶)公式: 给定点 ,其贝塞尔曲线即是两点间的线段,等同于线性插值: B(t)=(1-t)P_{0}+tP_{1},t\in [0,1] 通俗的来讲,n阶的贝塞尔曲线就是被2个固定点(起始与终止点)以及(n-1)个可拖动支点控制的均匀线段。也就是说n阶曲线需要(n+1)个点来确定。以下我以二阶贝塞尔曲线为例,阐述它的几何含义和简单推导。

如上图,设P_{0}P_{0}^{2}P_{2}是一条抛物线上顺序三个不同的点。过P_{0}P_{2}点的两切线交于P_{1}点,在P_{0}^{2}点的切线交P_{0}^{1}P_{2}^{1}P_{0}^{1}P_{1}^{1},且根据抛物线的切线定理,线段具有以下比例:

P_{0}P_{2}固定,引入线段的比例参数t,令以上等式的比值为 t:(1-t),则其中t取值区间为[0,1],有以下三个恒等式:

将①,②式代入③式中,得到: P_{0}^{2}=(1-t)^{2}P_{0}+2t(1-t)P_{1}+t^{2}P_{2} 当t从0增加到1时,它表示了由三个点P_{0}P_{1}P_{2}定义的一条二次贝塞尔曲线。这时的P_{0}P_{2}相当于上文说的固定点,P_{1}相当于可拖动的支点。
有了这个线段比例,和切线定理的基础概念,我们来解析一下三阶贝塞尔曲线,它的路径是这样绘制出来的(注意切点 “X” 的路径):
明白了绘图原理,不难作出更高阶的贝塞尔曲线,比如四阶/五阶的贝塞尔曲线:

右上可见,虽然贝塞尔曲线只是简单的二维函数,但是它的不管是弹性效果,还是速度表现上都十分的Amazing!它可以用来描绘曲面的平滑度,还可以用来体现物体非线性的不规则运动方式。怪不得 UI/动画/动效 大佬们都喜欢使用贝塞尔曲线来创造各种充满动感和节奏的设计,在函数本质上看它确实足够丝滑!

如何使用贝塞尔曲线

小伙伴们平时在 PS/ PR剪辑/ PPT/ CSS/ 即使简单地做个思维导图,当中应该都用到过贝塞尔曲线,例如钢笔工具、视频转场时的插值——缓入缓出、PPT非线性动画、网页Logo或者动态表单……贝塞尔曲线可谓是大有所用!在此分享一个开篇所示的使用案例

前端设计案例

在编码之前,首先简单了解一下CSS3中的transition-timing-function,它用于设置对象中过渡的动画类型/函数,或者说是在规定时间内的变化速度。transition-timing-function 的值有如下六种(其实本质就一种,即三阶贝塞尔曲线cubic-bezier):

效果 函数值
ease 缓慢开始,变快,减速结束 (0.25,0.1,0.25,1)
ease-in 缓慢开始 (0.42,0,1,1)
ease-out 缓慢结束 (0,0,0.58,1)
ease-in-out 以上两者结合,缓入缓出 (0.42,0,0.58,1)
linear 匀速 (0,0,0.58,1)
cubic-bezier 自定义 (X_{1},Y_{1},X_{2},Y_{2})

这里的(X1,Y1,X2,Y2)即是除去固定点 (0,0),(1,1) 外的两个支点,X的取值范围为[0,1],Y取值没有限制。 拿5个div来对比一下 linear|ease|ease-in|ease-out|ease-in-out 的差别:

回到表中,从ease和ease-in-out的描述效果看,都是缓入缓出,但是ease比起ease-in-out更像是在路上开车,调皮地弹射起步,糟糕又到了下个红灯路口前,持续减速停车。ease-in-out则是悠哉悠哉地开车方式:

我们来尝试找一下适合做按钮背景变化的三阶贝塞尔曲线的值。经过不断刷新查看效果来筛选,可以找出一个差不多的变化: cubic-bezier(0.31, -0.105, 0.43, 1.59) 它的函数图像如下:

0.5s内的运动变化(对比ease-in-out)如下(有一个回弹效果,非常棒!):

准备工作就绪,直接开始实践:

  1. 添加社交图标的链接,这里为了方便直接套用bootstrap的CSS样式以及引入Font Awesome,只需要添加cdn加载方式即可:
<link href="//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  1. 创立div,分别加入facebook、twitter、google的 fa 图标:
<div class="social-btns">
    <a class="btn facebook" href="#"><i class="fa fa-facebook"></i></a>
    <a class="btn twitter" href="#"><i class="fa fa-twitter"></i></a>
    <a class="btn google" href="#"><i class="fa fa-google"></i></a>
</div>
  1. 设置图标颜色(拾色获取)、div居中、背景、透明度、边框等等CSS样式:

* {
  margin: 0;
  padding: 0;
  list-style-type: none;
}
a,img {
  border: 0;
}
body {
  background: #eee;
}
.social-btns {
  height: 90px;
  margin: 80px auto;
  font-size: 0;
  text-align: center;
}
.social-btns .btn {
  display: inline-block;
  background-color: #fff;
  width: 90px;
  height: 90px;
  line-height: 90px;
  margin: 0 10px;
  text-align: center;
  position: relative;
  overflow: hidden;
  border-radius: 28%;
  box-shadow: 0 5px 15px -5px rgba(0, 0, 0, 0.1);
  opacity: 0.99;
}
.social-btns .btn .fa {
  font-size: 38px;
  vertical-align: middle;
}
  1. 设置前后图标背景色的变换效果,为动画做准备:
.social-btns .btn.facebook:before {
  background-color: #3b5998;
}
.social-btns .btn.facebook .fa {
  color: #3b5998;
}
.social-btns .btn.twitter:before {
  background-color: #00aff0;
}
.social-btns .btn.twitter .fa {
  color: #00aff0;
}
.social-btns .btn.google:before {
  background-color: #dc4a38;
}
.social-btns .btn.google .fa {
  color: #dc4a38;
}
  1. 设置核心动画效果,动作解构:利用有背景色的盒子通过贝塞尔运动(cubic-bezier)以及旋转(rotate)45deg 进入图标框中,期间加上图标放大缩小(scale)以及变换颜色的细节,慢镜头如下:

对比普通的运动方式,果然还是贝塞尔曲线的有巧克力般丝滑的味道呀……

这个动画效果的CSS代码:

.social-btns .btn, .social-btns .btn:before, .social-btns .btn .fa {
  transition: all 0.35s;
  transition-timing-function: cubic-bezier(0.31, -0.105, 0.43, 1.59);
}
.social-btns .btn:before {
  top: 90%;
  left: -110%;
}
.social-btns .btn .fa {
  transform: scale(0.8);
}
.social-btns .btn:focus:before, .social-btns .btn:hover:before {
  top: -10%;
  left: -10%;
}
.social-btns .btn:focus .fa, .social-btns .btn:hover .fa {
  color: #fff;
  transform: scale(1);
}
.social-btns .btn:before {
  content: "";
  width: 120%;
  height: 120%;
  position: absolute;
  transform: rotate(45deg);
}

至此,这样一个不错的按钮效果就全部完成啦,回顾编码过程,最核心的其实只有一点,找到合适的运动函数:

transition-timing-function: cubic-bezier(0.31, -0.105, 0.43, 1.59);

怪不得常言道 “学好数理化,干前后端都不怕”。CSS案例的分享就到这里了,如果有对于本文的问题都可以联系我交流~ 自己有一个学习分享的公众号,在文章末尾有介绍。

PPT演示文档

PPT中也是存在贝塞尔曲线的应用的。如下是我利用PPT制作的一个的公众号文章分割条,十分简陋。

在PPT中,动画的动作都是使用VBA编程好了的,如果想要自己定义,可以添加一个“动画大师”的插件,它包装好了VBA程序,将各个预设动作解构重组。这里的效果就是给每个小球添加简单的贝塞尔“缓入缓出”动作,然后设置延迟序列,即可达到动态追逐的效果。相对于敲代码而言,使用工具的体验是相当好的。

写在最后

还有其他的很多的关于贝塞尔曲线的应用,能力有限也就不一一细数啦。如果你觉得文章还可以,记得来这里专注一下新人。公众号:单调区间。在这里我会分享各种有趣的 前 / 后端 / 各类设计软件 的小知识,等你来玩。

参考

文章:

贝塞尔曲线总结: blog.csdn.net/tianhai110

抛物线中切线三角形的性质: lanqi.org/interests/2…

CSS cubic-bezier()函数: www.runoob.com/cssref/func…

CSS案例代码:

我的cdp分享:codepen.io/sansheng93/…

工具网站:

三阶贝塞尔在线演示: cubic-bezier.com/

在线LaTeX公式编辑: www.codecogs.com/latex/eqned…