从贝塞尔曲线的计算感受数学建模的魅力
最后更新于 2022-05-03 20:38:00
最近在做前端可视化相关的东西,在完成动画效果时,遇到一个不是很好处理的问题,需要让一个元素在画布上以曲线的轨迹进行运动。因为动画这块之前基本也没有怎么接触过,做的也都是简单的线性动画效果,所以碰到这个需求点的时候觉得是有点难度的。
其实,要真的实现按照一定曲线轨迹运动的效果倒也不难,毕竟圆、椭圆方程在平时做布局计算的时候用的也挺多的。但是,用圆或者椭圆计算曲线相当于是找了个特殊场景,不具备通用性;另一方面,说到曲线的绘制,贝塞尔曲线是绕不开的,这也是非常值得考虑的方案。
动画帧计算
一段动画实际上是由多个静态帧组成的,当帧率达到人眼不可分辨的程度时(比如 60 FPS),就感觉像是一个无缝连续的视频在流畅的播放。而某一静态帧的状态用数学公式来表达如下:
y = F(t) (0 <= t <= 1)
那么对于一个物体从 x0 运动到 x1,如何计算 t 时刻的位置?按照我的思路来看,可以转化为以下数学公式:
F(t) = (x1 - x0)*t + x0 (0 <= t <= 1)
这么算其实是没错的,但这个公式在数学建模的角度来看,其实是不好的,后面以计算贝塞尔曲线上一点的坐标为例解释为什么。这里先给出线性贝塞尔曲线数学公式:
B(t) = (1 - t)P0 + tP1 (0 <= t <= 1)
贝塞尔曲线
贝塞尔曲线(Bézier curve)在工业设计领域是一个非常重要的存在,应用非常广泛,在计算机图形学领域中贝塞尔曲线也有很好的支持,例如 Canvas API 原生就有提供贝塞尔曲线的绘制接口。
贝塞尔曲线从概念上来看是很难理解的,如何转化为数学公式来计算贝塞尔曲线,而这个过程是什么样的,刚开始理解起来也是比较抽象的。先来看看其(二次贝塞尔曲线)数学定义:
其中 P0、P1、P2 分别为起点、控制点、终点。
那么,有了公式计算二次贝塞尔曲线上一点按理来说已经可以实现了,但在这里之所以用贝塞尔曲线这个比较难理解的数学模型来探讨,其实是为了最终得到一个简化的具有普适性的解决动画帧计算的数学模型。对于熟悉动画计算的人来说,很多文档中对于开头提出的问题给出的数学公式为以下:
F(t) = (1 - t)*x0 + t*x1 (0 <= t <= 1)
这个时候,你会发现无论是以上公式,还是一次、二次或更高次的贝塞尔曲线公式中都有一个类似的元素即 1 - t。当然,公式都是相互推导以不同形式展现的,即:
F(t) = (1 - t)*x0 + t*x1 = (x1 - x0)*t + x0 (0 <= t <= 1)
公式相等是本质,但不同的展现形式蕴含的思维模式不同(或者说有没有利用好数学建模来进行问题的抽象)。以上面的公式来分析,前者表达的是 x0 与 x1 分别在 t 时刻状态的叠加,后者则表达的是起始状态 x0 叠加从 x0 运动到 x1 过程中 t 时刻的状态。从其蕴含的思维模式来分析,前者关注的是结果,后者则先分析过程再得到结果。
其实,说到这里,我觉得一个好的数学建模思维的魅力已经体现出来了,动画帧计算应尽可能的简单且关注核心问题,不要被过程所迷惑,这也是为何很多文档中的公式包含 1 - t 元素的原因。