为冬奥加油——利用贝塞尔曲线实现冰墩墩
前言
冬奥会即将马上结束,我国体育健儿发挥优异,创造了我国参加冬奥会的新纪录。在冬奥即将结束之际,我们一起来绘制火出天际的冰墩墩,为我国体育健儿喝彩,当然也可以为自己收获一只可爱的冰墩墩。
学习本文,你可以收获:
理解贝塞尔曲线
学会
canvas
中绘制二阶贝塞尔曲线和三阶贝塞尔曲线的方法获得墩各曲线的数据,成功拥有你的墩。
分析
首先我们整体看一下封面图,大致会有两种实现思路。
方案一: 基于
CSS
实现
冰墩墩大部分部位都可以使用 CSS
的椭圆角配合为元素来模拟实现,比如眼睛、能量圈等,但有两个问题。
轮廓实现问题: 小包观摩了大佬们的创意,大佬将冰墩墩进行拆分,将耳朵手臂等部位单独拆分出来,形象化一下冰墩墩,实现的冰墩墩非常可爱。小包仔细的思考了一下,好像也没有什么创新点。
椭圆尺寸问题: 小包找到一张比较简单的简笔画,但是测量各个椭圆的尺寸也是个大麻烦。
方案二: 基于
canvas
实现
canvas stroke()
方法会实际地绘制出通过 moveTo()
和 lineTo()
等方法定义的路径。
绘制曲线的方法找到了,接下来我们需要找到这种曲线的类别是什么?
二维数学空间中存在贝塞尔曲线,贝塞尔曲线就可以胜任整个冰墩墩的绘制。那什么是贝塞尔曲线那?我们又如何求解出贝塞尔曲线? 下面我们来一起学习一下。
贝塞尔曲线
贝塞尔曲线(
Bezier curve
),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。贝塞尔曲线是计算机图形学中相当重要的参数曲线,在一些比较成熟的位图软件中也有贝塞尔曲线工具,如PhotoShop
等 ———— 百度百科
定义这是嘛玩意啊?一头雾水。接下来来看几个案例,深入了解一下各阶贝塞尔曲线。
贝塞尔曲线根据控制点的数量可以分为:
一阶贝塞尔曲线 (2 个控制点)
二阶贝塞尔曲线 (3 个控制点)
三阶贝塞尔曲线 (4 个控制点)
四阶贝塞尔曲线 (5 个控制点)
n 阶贝塞尔曲线 (n + 1 个控制点)
跟随着上面的动画,不知道是否对贝塞尔曲线产生了一定的理解?不急下面小包慢慢道来~
贝塞尔曲线中有个重要的参数 t
,取值 [0,1]
,t
参数的值等于线段上某一个点距离起点的长度除以线段长度。现在对 t
的理解有可能有些空洞,下面我们通过具体案例深入理解一下。
一阶贝塞尔曲线
一阶贝塞尔曲线包括两个控制点 、,两控制点连接成线段 。
在一阶贝塞尔曲线中,只有一条线段,,对于每一个 t
值,都可以获得一个贝塞尔曲线上的点。因此随着 t
从 0 -> 1
,就可以绘制出一阶贝塞尔曲线。
根据几何知识,我们可以求解出一阶贝塞尔曲线的公式为:
一阶贝塞尔曲线总结一下就是随着参数 t 增大,贝塞尔曲线上的点从线段一端移动到另一端。
二阶贝塞尔曲线
二阶贝塞尔曲线分别有三个控制点,、、,二阶贝塞尔曲线两条线段 、。t
参数的值等于线段上某一个点距离起点的长度除以线段长度,且所有的线段上都要满足上述要求,因此在两个线段上分别取点 和 ,且满足 , 和 构成新的线段,仍要满足 t 值,因此通过 值可以求得位于贝塞尔曲线上的点 。随着 t
从 0 -> 1
,就可以绘制出二阶贝塞尔曲线。
根据上面的计算流程,我们可以一步一步推出二阶贝塞尔曲线的公式:
利用一阶公式可以求解出 和
然后求解出 ,也就是第一步求解结果代入一阶共公式中:
二阶贝塞尔曲线的公式如下:
三阶贝塞尔曲线
三阶贝塞尔曲线有四个控制点,类似于二阶贝塞尔曲线的求解过程。
分别在线段 、、 上取点 ,且
点 组成新的线段 ,在两端线段上分别取点 ,且满足
点 组成线段 ,取点 ,且满足
依次带入公式,可以求得三阶贝塞尔曲线的公式
分别代表图中的
其余多阶贝塞尔曲线是类似的原理,利用贝塞尔曲线我们可以创造很多可爱、炫酷的图形。
反推贝塞尔曲线控制点
下面只是小包的个人思考过程,数学大佬轻喷。
目前我们拥有了墩的样板,因此我们需要反推墩上每段贝塞尔曲线的控制点。求解出控制点后,我们就可以利用 canvas
绘制每段曲线,最终组成可爱的墩。
首先各阶贝塞尔曲线都有两个固定的控制点——曲线的起始点和终止点。
那么一阶贝塞尔曲线控制点就是起止点。
二阶贝塞尔曲线控制点分别是起止点及起止点处切线交点。
三阶贝塞尔曲线有四个控制点,其中两个是起止点。另外两个控制点是起止点处切线及曲线极值点处切线相交点。
问题来了,虽然思考出贝塞尔曲线的控制点寻找方法,但小包却没有找到如何求出各段曲线的控制点。那该如何通过上面的算法进行测量那?奈何小包的 PS 水平太差,没找到合适的测量手段,所幸有大佬测量过。
膜拜大佬,下面是大佬的测量过程。
小包将大佬的测量数据进行汇总,得出下表格:
我们得到了每段贝塞尔曲线的控制点,下面就开始绘制吧。
canvas 的贝塞尔曲线方法
实现冰墩墩主要使用两个贝塞尔方法: bezierCurveTo
quadraticCurveTo
quadraticCurveTo
quadraticCurveTo
方法用于绘制二阶贝塞尔曲线,使用语法
cpx/cpy
为控制点的坐标,x/y
为结束点坐标。
二阶贝塞尔曲线共需要三个控制点,因此使用
quadraticCurveTo
会基于当前路径的结束点继续绘制。如果不存在路径,需要使用beginPath()
和moveTo()
方法来定义起始点。
使用案例:
bezierCurveTo
bezierCurveTo
方法用于绘制三阶贝塞尔曲线,使用语法
cpx1/cpy1,cpx2/cpy2
为控制点的坐标,x/y
为结束点坐标。
与
quadraticCurveTo
方法相同,方法基于当前路径的结束点继续绘制。如果不存在路径,需要使用beginPath()
和moveTo()
方法来定义起始点。
使用案例:
冰墩墩绘制
准备工作
由于大佬测量参数太大,因此小包首先对数据做了一下缩放。并封装一下常用函数。
轮廓绘制
轮廓绘制非常简单,我们只需按照测量数据,调用 canvas
的贝塞尔曲线绘制方法即可。
通过上面的代码,我们就可以成功的绘制出墩的轮廓了!!!
绘制耳朵
绘制冰墩墩小手小脚
其余部分的墩绘制都是调用 canvas
的 bezierCurveTo
及 quadraticCurveTo
方法,小包就不在文章中重复了,具体可以参考源码或者添加小包索要汇总数据表。
绘制黑眼圈
绘制能量圈
其余冰墩墩部分绘制都是调用 canvas
的 bezierCurveTo
及 quadraticCurveTo
方法,与上文实现类似,小包就不在文章中重复了,具体可以参考源码或者添加小包索要汇总数据表。
源码仓库
源码地址: 可爱冰墩墩源码
体验地址:可爱冰墩墩在线版
如果感觉有帮助的话,别忘了给小包点个 ⭐ 。
参考链接
后语
我是 战场小包 ,一个快速成长中的小前端,希望可以和大家一起进步。
如果喜欢小包,可以在 infoQ 关注我,也可以在我的小小公众号——小包学前端关注小包的日常分享。
一路顺利,冲向未来!!!
冰墩墩绘制只用作文章发布,为冬奥喝彩。不要用作其他途径
版权声明: 本文为 InfoQ 作者【战场小包】的原创文章。
原文链接:【http://xie.infoq.cn/article/b7367967a0d5c214da0471f39】。文章转载请联系作者。
评论