canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动


Posted in HTML / CSS onJanuary 10, 2018

写在最前

在之前的这篇文章中我们提到了对于贝塞尔公式的运用。本次分享一下如何推导贝塞尔公式以及附一个简单的?即小球跟随曲线轨迹运动。

效果预览

canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动

在本例中生成的曲线由以上文章中的源码提供。

贝塞尔曲线公式推导

canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动

上面这张图是贝塞尔曲线的完整公式,看起来一脸懵逼=。=,因为这是N阶的推导公式,本次我们以一二阶贝塞尔公式的推导来理解一下这个推导公式的由来。先来看下网上流传已久的几张贝塞尔动图:

canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动

canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动

canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动

在这三张图中最重要的部分是我们需要理解变量t。t的取值范围是0-1。从上面的gif中也可以看出来似乎曲线的绘制过程就是t从0到1的过程。嗯其实就是这样的。t的真实含义是什么呢?

在p0p1、p1p2、p2p3等等的起点到控制点再到终点的连线中,每段连线都被分割成了两部分(仔细看动图中的黑色、绿色、蓝色圆点),各段连线中两部分的比值都是相同的,比值范围是0到1,而这个比值就是t

来看下面的一阶贝塞尔曲线示意图:

canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动

pt是p0p1上的任意一点,p0pt / ptp1 = t。从而我们可以引出下面的推导

canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动

此时t为时间,v为速度。我们可以看做从p0到p1的距离等于固定速度乘以固定时间

canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动

故到p上某一点的时间为固定的速度乘以某个时间值。同时固定的速度已经已经可以表示为上面的推导公式。此时等式右边就形成了t(0,1) / t;即相当于某个时间值 / 固定时间值,即产生了我们一开始所强调的变量t,其取值范围为[0,1]。从而下面的等式也就比较好理解了。

canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动

至此一阶贝塞尔曲线我们已经推到了出来,其中变量为起点、终点与比值t。

那么二阶公式如何从一阶过渡过去呢?

来看下面这张图:

canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动

其中Pp(t)的经过路径就是我们所求的二阶贝塞尔曲线,那么其实我们也可以将其从一阶进行演变:

canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动

我们先将pa、pb两个点所连线段当做一阶曲线,之后再由两端一阶曲线分别表示pa、pb,最后就得到了我们的二阶曲线公式。仔细观察就能发现这和我们最初的完整公式是相同的:

canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动

其中n选择不同数值时就可以得出不同阶的曲线公式。同时从上面的推导过程也可以知道,不论是几阶曲线,我们都可以完全由一阶来表示,而这个“表示”的过程就是我们在上面看到的形成动画中那些辅助线。故可以感受下作者自己写的曲线形成动画中的效果,每段辅助线均由一阶曲线形成:

canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动

相关地址

物体跟随复杂曲线轨迹运动

当我们知道曲线的公式有何而来之后,如何让小球沿着曲线运动就很好理解了。我们生成的每段曲线都是可以用公式表示出来的,也正因如此我们就可以得到每个t值时的曲线坐标点。从而知道物体的绘制坐标。

//核心逻辑
LinearGradient.prototype.drawBall = function() {
    var self = this
    var item = ctrlNodesArr[ctrlDrawIndex] 
    //存储了各段曲线的控制点
    //各段曲线均为三阶贝塞尔,故下面计算x,y值代入到了三阶公式中
    var ctrlAx = item.cAx,//各个控制点
        ctrlAy = item.cAy,
        ctrlBx = item.cBx,
        ctrlBy = item.cBy,
    ...
    if(item.t > 1) {
        ctrlDrawIndex++ //当一段曲线的t>1说明曲线已经走到头
    }else {
        self.ctx.clearRect(0, 0, self.width, self.height)
        item.t += 0.05
        var ballX = ox * Math.pow((1 - item.t), 3) + 3 * ctrlAx * item.t * Math.pow((1 - item.t), 2) + 3 * ctrlBx * Math.pow(item.t, 2) * (1 - item.t) + x * Math.pow(item.t, 3)
        var ballY = oy * Math.pow((1 - item.t), 3) + 3 * ctrlAy * item.t * Math.pow((1 - item.t), 2) + 3 * ctrlBy * Math.pow(item.t, 2) * (1 - item.t) + y * Math.pow(item.t, 3)
        //代入三阶贝塞尔曲线公式算出小球的坐标值
        self.ctx.beginPath()
        self.ctx.arc(ballX, ballY, 5, 0, Math.PI * 2, false)
        self.ctx.fill()
    }
    if(ctrlDrawIndex !== ctrlNodesArr.length) {
        window.requestAnimationFrame(newMap.drawBall.bind(self))
    }
}

最后

demo地址:这里✨✨

源码地址:欢迎star

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

HTML / CSS 相关文章推荐
纯CSS3编写的的精美动画进度条(无flash/无图像/无脚本/附源码)
Jan 07 HTML / CSS
利用css3制作3D样式按钮实现代码
Mar 18 HTML / CSS
使用css3实现的windows8开机加载动画
Dec 09 HTML / CSS
关于css兼容性问题及一些常见问题汇总
May 03 HTML / CSS
CSS3条纹背景制作的实战攻略
May 31 HTML / CSS
CSS 3.0 结合video视频实现的创意开幕效果
Jun 01 HTML / CSS
html5+CSS3+JS实现七夕言情功能代码
Aug 28 HTML / CSS
HTML5 拖拽批量上传文件的示例代码
Mar 28 HTML / CSS
HTML5中div、article、section的区别及使用介绍
Aug 14 HTML / CSS
HTML5+JS实现俄罗斯方块原理及具体步骤
Nov 29 HTML / CSS
基于canvas使用贝塞尔曲线平滑拟合折线段的方法
Jan 10 HTML / CSS
Html5 canvas实现粒子时钟的示例代码
Sep 06 HTML / CSS
基于canvas使用贝塞尔曲线平滑拟合折线段的方法
Jan 10 #HTML / CSS
canvas实现高阶贝塞尔曲线(N阶贝塞尔曲线生成器)
Jan 10 #HTML / CSS
H5混合开发app如何升级的方法
Jan 10 #HTML / CSS
浅谈关于html5中图片抛物线运动的一些心得
Jan 09 #HTML / CSS
详解快速开发基于 HTML5 网络拓扑图应用
Jan 08 #HTML / CSS
浅谈HTML5 Web Worker的使用
Jan 05 #HTML / CSS
详解基于canvas的视频遮罩插件
Jan 04 #HTML / CSS
You might like
雄兵连:天使彦天使彦为爱折翼,彦和炙心同时念动的誓言!
2020/03/02 国漫
php 保留字列表
2012/10/04 PHP
jQuery 技巧大全(新手入门篇)
2009/05/12 Javascript
juqery 学习之三 选择器 可见性 元素属性
2010/11/25 Javascript
JS window对象的top、parent、opener含义介绍
2013/12/03 Javascript
js中继承的几种用法总结(apply,call,prototype)
2013/12/26 Javascript
JavaScript中字符串(string)转json的2种方法
2015/06/25 Javascript
JS实现新浪微博效果带遮罩层的弹出框代码
2015/10/12 Javascript
js判断手机号是否正确并返回的实现代码
2017/01/17 Javascript
JS 插件dropload下拉刷新、上拉加载使用小结
2017/04/13 Javascript
详解Vue微信公众号开发踩坑全记录
2017/08/21 Javascript
AngularJs 禁止模板缓存的方法
2017/11/28 Javascript
关于JavaScript语句后面的分号问题
2017/12/07 Javascript
vue工程全局设置ajax的等待动效的方法
2019/02/22 Javascript
Node.js中Koa2在控制台输出请求日志的方法示例
2019/05/02 Javascript
微信小程序点击列表跳转到对应详情页过程解析
2019/09/26 Javascript
Vue.extend 编程式插入组件的实现
2019/11/18 Javascript
Vue+element+cookie记住密码功能的简单实现方法
2020/09/20 Javascript
[42:52]Optic vs Serenity 2018国际邀请赛淘汰赛BO3 第二场 8.22
2018/08/23 DOTA
[01:19:46]DOTA2-DPC中国联赛 正赛 SAG vs DLG BO3 第一场 2月28日
2021/03/11 DOTA
Python的randrange()方法使用教程
2015/05/15 Python
Python函数返回值实例分析
2015/06/08 Python
在Python的struct模块中进行数据格式转换的方法
2015/06/17 Python
基于python内置函数与匿名函数详解
2018/01/09 Python
pytorch 更改预训练模型网络结构的方法
2019/08/19 Python
Python面向对象封装操作案例详解
2019/12/31 Python
python图片指定区域替换img.paste函数的使用
2020/04/09 Python
香港礼品网站:GiftU eshop
2017/09/01 全球购物
英国日常交易网站:Wowcher
2018/09/04 全球购物
进程的查看和调度分别使用什么命令
2013/12/14 面试题
函授毕业自我鉴定
2013/12/19 职场文书
大学社团计划书
2014/05/01 职场文书
2014年民警工作总结
2014/11/25 职场文书
小学运动会入场口号
2015/12/24 职场文书
Web前端:CSS最强总结 附详细代码
2021/03/31 HTML / CSS
mybatis中sql语句CDATA标签的用法说明
2021/06/30 Java/Android