初识贝塞尔(bezier)曲线
文章目录
- 资料援引
- 贝塞尔曲线的用途
- 一阶贝塞尔(bezier)曲线
- 二阶贝塞尔(bezier)曲线
- 三阶贝塞尔(bezier)曲线
- 高阶贝塞尔(bezier)曲线
- 三阶贝塞尔曲线求插值(Slerp)
资料援引
B站视频:wow,神奇的贝塞尔曲线!
博客:贝塞尔曲线简单介绍
知乎:曲线篇: 贝塞尔曲线
贝塞尔曲线的用途
- 基于对汽车的的车身结构进行流体化设计而诞生
- 处理视频状态点之间的图像变化
- 随心所欲绘制曲线,比如:
一阶贝塞尔(bezier)曲线
如上,P0P_0P0、P1P_1P1 两点构成了一条线段,而我们可以通过一个函数——线性插值(lerp),来根据一个 ttt 值(t∈[0,1]t \in [0,1]t∈[0,1]) 得到线段上一点 PPP(图中一直在滑动的点)。而 PPP 的运动轨迹(红线),便是一阶贝塞尔线段(曲线)。线性插值的数学形式(一阶贝塞尔曲线公式)为:
P=lerp(P0,P1,t)=(1−t)P0+tP1P=lerp(P_0,P_1,t)=(1-t)P_0 + tP_1P=lerp(P0,P1,t)=(1−t)P0+tP1
一阶贝塞尔曲线有两个端点(P0P_0P0、P1P_1P1 ),0个控制点。
二阶贝塞尔(bezier)曲线
如上,假设现在有点 P2P_2P2 ,它与 P1P_1P1 构成了新的线段,我们得到两个 一阶插值点(Q1Q_1Q1、Q2Q_2Q2),它们构成了绿色线段,值得注意的是,两个插值点具有相同的 ttt 值。
而此时我们在绿色线段上生成一个 二阶插值点(PPP),并让它具有 与两个一阶插值点相同的ttt 值。 那么该点的运动轨迹就是 二阶贝塞尔曲线。其公式推导为:
- 绿色线段左端点的运动轨迹:
Q1=(1−t)P0+tP1Q_1 = (1-t)P_0 + tP_1 Q1=(1−t)P0+tP1
- 绿色线段右端点的运动轨迹:
Q2=(1−t)P1+tP2Q_2 = (1-t)P_1 + tP_2Q2=(1−t)P1+tP2
- 二阶贝塞尔曲线公式:
P=(1−t)Q1+tQ2P = (1-t)Q_1 + tQ_2P=(1−t)Q1+tQ2
=(1−t)((1−t)P0+tP1)+t((1−t)P1+tP2)=(1-t)((1-t)P_0 + tP_1) + t((1-t)P_1 + tP_2)=(1−t)((1−t)P0+tP1)+t((1−t)P1+tP2)
=(1−t)2P0+2t(t−1)P1+t2P2=(1-t)^2P_0+2t(t-1)P_1+t^2P_2=(1−t)2P0+2t(t−1)P1+t2P2
二阶贝塞尔曲线有两个端点(P0P_0P0、P2P_2P2),一个控制点(P1P_1P1)。
三阶贝塞尔(bezier)曲线
经过对一阶、二阶贝塞尔曲线的研究学习,我们能知道贝塞尔曲线通过在两点之间再采点的方式实现降阶,每一次选点都是一次的降阶。
- P0P_0P0、P1P_1P1、P2P_2P2、P3P_3P3 通过生成插值点 Q1Q_1Q1、Q2Q_2Q2、Q3Q_3Q3 来构成二阶贝塞尔(绿色线段)
- 在此基础上生成插值点 O1O_1O1、O2O_2O2 来构成一阶贝塞尔(蓝色线段)
- 之后以 O1O_1O1、O2O_2O2 上的插值点 PPP 的运动轨迹来生成三阶贝塞尔曲线。
公式推导过程同二阶贝塞尔曲线,因此不做赘述,直接贴出公式:
P=(1−t)3P0+3t(1−t)2P1+3t2(1−t)P2+t3P3P=(1-t)^3P_0+3t(1-t)^2P_1+3t^2(1-t)P_2+t^3P_3P=(1−t)3P0+3t(1−t)2P1+3t2(1−t)P2+t3P3
三阶贝塞尔曲线有两个端点(P0P_0P0、P3P_3P3),两个控制点(P1P_1P1、P2P_2P2)。
高阶贝塞尔(bezier)曲线
- 四阶贝塞尔曲线示意图:
- 五阶贝塞尔曲线示意图:
- 高阶贝塞尔曲线公式:
P(t)=∑i=0nPiBi,n(t),t∈[0,1]P(t)=\sum_{i=0}^{n}P_iB_{i,n}(t),t \in [0,1]P(t)=i=0∑nPiBi,n(t),t∈[0,1]
Bi,n(t)=Cniti(1−t)n−i=n!i!(n−i)!ti(1−t)n−i,【i=0,1,...,n】B_{i,n}(t)=C_n^it^i(1-t)^{n-i}=\frac{n!}{i!(n-i)!}t^i(1-t)^{n-i},【i=0,1,...,n】Bi,n(t)=Cniti(1−t)n−i=i!(n−i)!n!ti(1−t)n−i,【i=0,1,...,n】
三阶贝塞尔曲线求插值(Slerp)
在熟悉了贝塞尔曲线的相关概念之后,我们来了解一下它的具体应用。通常它的应用场景是:
已知两个端点和两个控制点的情况下,根据 动画进度向量 PxP_xPx 求 ttt,再由 ttt 确认的曲线求 PyP_yPy。
回顾一下三阶贝塞尔曲线公式:
P=(1−t)3P0+3t(1−t)2P1+3t2(1−t)P2+t3P3P=(1-t)^3P_0+3t(1-t)^2P_1+3t^2(1-t)P_2+t^3P_3P=(1−t)3P0+3t(1−t)2P1+3t2(1−t)P2+t3P3
公式中的 P0P_0P0、P1P_1P1 等都是二维向量,由两个一维向量 PxP_xPx 和 PyP_yPy 构成。而我们根据 ttt 求 PPP,本质上是根据 ttt 来求一个坐标 (x,y)(x,y)(x,y)。因此,可将公式拆解在两个一维向量上:
y=(1−t)3Py0+3t(1−t)2Py1+3t2(1−t)Py2+t3Py3y=(1-t)^3P_{y0}+3t(1-t)^2P_{y1}+3t^2(1-t)P_{y2}+t^3P_{y3}y=(1−t)3Py0+3t(1−t)2Py1+3t2(1−t)Py2+t3Py3
x=(1−t)3Px0+3t(1−t)2Px1+3t2(1−t)Px2+t3Px3x=(1-t)^3P_{x0}+3t(1-t)^2P_{x1}+3t^2(1-t)P_{x2}+t^3P_{x3}x=(1−t)3Px0+3t(1−t)2Px1+3t2(1−t)Px2+t3Px3
而由于我们在处理动画时通常起点 P0P_0P0 和终点 P3P_3P3 都是可以确定的【P0(0,0)、P3(1,1)P_0(0,0)、P_3(1,1)P0(0,0)、P3(1,1)】,因此上述公式可以化简为(以 xxx 举例,yyy 同理):
x=3t(1−t)2Py1+3t2(1−t)Py2+t3x=3t(1-t)^2P_{y1}+3t^2(1-t)P_{y2}+t^3x=3t(1−t)2Py1+3t2(1−t)Py2+t3
完全展开:
=3Py1t−6Py1t2+3Py1t3+3Py2t2−3Py2t3+t3=3P_{y1}t-6P_{y1}t^2+3P_{y1}t^3+3P_{y2}t^2-3P_{y2}t^3+t^3=3Py1t−6Py1t2+3Py1t3+3Py2t2−3Py2t3+t3
提取三次方系数 aaa:
a=3Py1−3Py2+1a=3P_{y1}-3P_{y2}+1a=3Py1−3Py2+1
提取二次方系数 bbb:
b=3Py2−6Py1b=3P_{y2}-6P_{y1}b=3Py2−6Py1
提取一次方系数 ccc:
c=3Py1c=3P_{y1}c=3Py1
将公式简化为:
x=at3+bt2+ctx=at^3+bt^2+ctx=at3+bt2+ct
移动 xxx,将公式变为一元三次方程:
at3+bt2+ct−x=0at^3+bt^2+ct-x=0at3+bt2+ct−x=0
此时,就可以通过卡尔丹公式根据 xxx 求出来 ttt。之后根据 ttt 可以求得 yyy:
y=(1−t)3Py0+3t(1−t)2Py1+3t2(1−t)Py2+t3Py3y=(1-t)^3P_{y0}+3t(1-t)^2P_{y1}+3t^2(1-t)P_{y2}+t^3P_{y3}y=(1−t)3Py0+3t(1−t)2Py1+3t2(1−t)Py2+t3Py3
代码实现:
double SlerpWithCubicBazier(double pX1, double pY1, double pX2, double pY2, double x) {// x为动画进度,并不是t,t只是一个参数,先根据x求t,再由t确认的曲线上求y// 参考 https://github.com/gre/bezier-easing/blob/master/src/index.jsdouble t = 0.0;if (x <= 0.0) {t = 0.0;}else if (x >= 1.0) {t = 1.0;}else {// x = (1-t)^3*P0x + 3*(1-t)^2*t*P1x + 3*(1-t)*t^2*P2x + t^3*P3x// 提取系数:double a = 0.0 + 3 * pX1 - 3 * pX2 + 1.0;double b = 3 * 0.0 - 6 * pX1 + 3 * pX2;double c = 0.0 + 3 * pX1;// 公式可化简为: x = at^3 + bt^2 + ct// 转换为基于 t 的一元三次方程:at^3 + bt^2 + ct - x = 0double d = 0 - x;// 那么就可以通过 SolveCubic 函数根据a、b、c、d四个系数来求解一元三次方程的一个实根// 可能该一元三次方程的根不止一个,但不重要,即使有多个根我们也只需要其中之一,且要求这个根是在 0~1 之间的,符合 t 的取值范围要求,如果没有根/没有符合要求的根我们会返回 -1double tTemp = SolveCubic(a, b, c, d);if (tTemp == -1) {return -1;}t = tTemp;}// Gy(t) = P0*(1-t)^3 + 3*P1*t*(1-t)^2 + 3*P2*t^2*(1-t) + P3*t^3 t[0,1]// PY0=0.0 PY3=1.0double coef1 = 0.0 * (1.0 - t) * (1.0 - t) * (1.0 - t);double coef2 = pY1 * 3 * t * (1.0 - t) * (1.0 - t);double coef3 = pY2 * 3 * t * t * (1.0 - t);double coef4 = 1.0 * t * t * t;double gt = coef1 + coef2 + coef3 + coef4;return gt;
}
SolveCubic
函数的具体实现如下,值得注意的是,并不能简单的将此函数的作用等同于求解一元三次方程,本函数的本质作用是贝塞尔曲线中根据 x
求出 t
,这两者有什么区别呢?举个具体的例子,下面的代码第 5 行有这样的语句:
if (d == 0) return 0;
- 在 d=0 的情况下,普通一元三次方程是可以继续求解的;
- 但是在
SlerpWithCubicBazier
调用SolveCubic
时,是以 d=0−xd=0-xd=0−x 的形式传值的,d=0d=0d=0 代表 x=0x=0x=0,此时曲线位于起点,t
的值可以确定,无需通过解方程获得,即 t=0t=0t=0。
double FCPSolveCubic(double a, double b, double c, double d) {/* a=0 视为一元二次方程式 */if (a == 0) return FCPSolveQuadratic(b, c, d);/* d=0表明x=0,则t=0*/if (d == 0) return 0;/* 将三次方的系数变为1,方便后续判别式中的计算,即不用考虑 a^2 这一项了 */b /= a;c /= a;d /= a;/* q和r对应求根公式中的p和q,dis即是求根公式的判别式 △ */double q = (3.0 * c - FCPSquared(b)) / 9.0;double r = (-27.0 * d + b * (9.0 * c - 2.0 * FCPSquared(b))) / 54.0;double disc = FCPCubed(q) + FCPSquared(r);double term1 = b / 3.0;if (disc > 0) {/* 运用卡尔丹公式求得一个实根 */double s = r + sqrtf(disc);s = (s < 0) ? - FCPCubicRoot(-s) : FCPCubicRoot(s);double t = r - sqrtf(disc);t = (t < 0) ? - FCPCubicRoot(-t) : FCPCubicRoot(t);double result = -term1 + s + t;if (result >= 0 && result <= 1) return result;} else if (disc == 0) {double r13 = (r < 0) ? - FCPCubicRoot(-r) : FCPCubicRoot(r);double result = -term1 + 2.0 * r13;if (result >= 0 && result <= 1) return result;result = -(r13 + term1);if (result >= 0 && result <= 1) return result;} else {q = -q;double dum1 = q * q * q;dum1 = acosf(r / sqrtf(dum1));double r13 = 2.0 * sqrtf(q);double result = -term1 + r13 * cos(dum1 / 3.0);if (result >= 0 && result <= 1) return result;result = -term1 + r13 * cos((dum1 + 2.0 * M_PI) / 3.0);if (result >= 0 && result <= 1) return result;result = -term1 + r13 * cos((dum1 + 4.0 * M_PI) / 3.0);if (result >= 0 && result <= 1) return result;}return -1;
}
上面代码中用到的知识:
- 一元三次方程判别式:
△=q24+p227△ = \frac{q^2}{4} + \frac{p^2}{27}△=4q2+27p2
- 标准型方程中卡尔丹公式的一个实根:
初识贝塞尔(bezier)曲线相关推荐
- Unity 工具类 之 贝塞尔 Bezier 曲线
Unity 工具类 之 贝塞尔 Bezier 曲线 目录 Unity 工具类 之 贝塞尔 Bezier 曲线 一.简单介绍 二.原理与分类 三.公式与原理图演示 五.注意事项 六.样例使用步骤(三次贝 ...
- 贝塞尔Bezier曲线的使用
1 简介 贝塞尔曲线就是这样的一条曲线,它是依据N个位置任意的点坐标绘制出的一条光滑曲线.那么,我们可以直观地认为,为了得到一条贝塞尔曲线,我们只要输入起点.终点及控制点既可.变化参数t都是位于[ ...
- C#绘制带控制点的Bezier曲线,用于点阵图像及矢量图形
[摘要]不借助第三方, 使用c# + GDI+进行SVG等绘图,绘制带控制点的Bezier曲线.可用于点阵图像及矢量图形(如SVG)绘图.先看效果: (不知为何,已两次上传图片,无法显示,求助csdn ...
- Bezier(贝塞尔)曲线小总结
在初学时,我发现Bezier曲线(中文名贝塞尔曲线,想要了解历史发展等的可以看此百度百科:贝塞尔曲线_百度百科)很难理解,故在此写了一篇自己的心得感悟.要理解它最重要的是理解Bernstein基函数. ...
- matlab 贝塞尔曲线,基于MATLAB动态实现Bezier曲线几何作图.pdf
基于MATLAB动态实现Bezier曲线几何作图.pdf 2015年 1月 黑龙江生态工程职业学院学报 Jan.2O15 第28卷第 1期 JournalofHeilongjiangVocationa ...
- 曲线数学NURBS之bezier曲线
最近新研究topic是NURBS,NURBS(Non Uniform Rational B-spline)即非均匀有理B样条曲线.往往提到B样条.以及NURBS就会提到bezier曲线,他们之间的关系 ...
- 样条之贝塞尔(Bezier)
我曾经发过两篇关于贝塞尔的文章:数学图形(1.47)贝塞尔(Bézier)曲线,数学图形之贝塞尔(Bézier)曲面.那是使用我自己定义的脚本语言生成贝塞尔图形.由于我自己定义的脚本语法功能有限,所以 ...
- 开源项目推荐:Bezier曲线、B-Spline和NURBS的区别与《THE NURBS BOOK 2nd》简介,曲线拟合可视化工具
一.基本概念 B-Spline:B样条曲线 NURBS(Non Uniform Rational B-Spline):非均匀有理B样条曲线 B样条曲线有三种类型: 当起始点和终止点的重复度为最高次数加 ...
- 【四足机器人--摆动相足端位置速度轨迹规划】(4.1)FootSwingTrajectory(bezier曲线计算脚的摆动轨迹)代码解析
系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录 前言 一.FootSwingTrajectory(bezier曲线)的内容 ...
- 轨迹规划——Bezier曲线与B样条曲线
一.Bezier曲线 1.Bezier曲线的背景 给定n+1个数据点,p0~pn,生成一条曲线,使得该曲线与这些点描述的形状相符. (如果要求曲线通过所有数据点,则属于插值问题:如果只要求曲线逼近这些 ...
最新文章
- Paddle网络结构中的层和模型
- matlab画图横纵轴刻度相关设置
- mysql面试常用命令_面试之MySQL基本命令
- 世界范围内糖化血红蛋白报告的3种建议形式
- linux在什么环境运行,Linux环境变量是什么
- 鸿蒙OS应用开发_基础篇_编写第一个HarmonyOs应用_体会HarmonyOs的一次开发多端部署_以及分布式任务调度_IDE安装_了解应用组件以及应用布局---HarmonyOs开发工作笔记001
- shell编程学习笔记之特殊变量($0、$1、$2、 $?、 $# 、$@、 $*)
- HttpClient 4.5.3 模拟登陆CSDN
- 方便好用的论文管理软件EndNote X9 + PDF阅读编辑器Adobe Acrobat DC(2)
- 实现计算机考试和vb交换的,2012江苏省计算机二级VB试题库及答案
- 如何绘制逻辑图 — 8.逻辑的表达:数据逻辑
- C语言 汉字名字排列组合
- 生物信息学入门之基本概念之蛋白质同源检测和折叠识别
- 计算机计算资产分析表,财务指标计算器.xls
- 物联网产品的发展简介(一)【产品篇01】
- web网页本地视频播放器
- win7搜索文件 服务器,win7系统搜索不到文件的解决方法
- android设备连接win10,win10手机连接Android设备、iphone 操作方法
- LessLyrics 苹果Mac歌词软件 iTunes歌词助手
- 云服务器和云虚拟主机有什么区别
热门文章
- Visual Studio Code中对某变量名批量修改
- How to add SMSC feature into Android
- dart 语言是jvm_为什么发明基于 Dart 语言的 flutter 作为跨平台开发?
- arch检验python_Python玩转金融时间序列之ARCH与GARCH模型
- 165体重_我身高165cm标准体重是多少斤
- O2OA二次开发办公平台:内容管理数据迁移
- 【Matplotlib】在Jupyter交互页面中绘制折线图对比(自用函数)
- Internet Explorer 11: “请不要再叫我 IE”
- 这发文助手智力有点低下啊
- php array_diff菜鸟,TCGA