初识贝塞尔(bezier)曲线

article/2025/11/9 17:52:55

文章目录

  • 资料援引
  • 贝塞尔曲线的用途
  • 一阶贝塞尔(bezier)曲线
  • 二阶贝塞尔(bezier)曲线
  • 三阶贝塞尔(bezier)曲线
  • 高阶贝塞尔(bezier)曲线
  • 三阶贝塞尔曲线求插值(Slerp)


资料援引

B站视频:wow,神奇的贝塞尔曲线!

博客:贝塞尔曲线简单介绍

知乎:曲线篇: 贝塞尔曲线


贝塞尔曲线的用途

  • 基于对汽车的的车身结构进行流体化设计而诞生
  • 处理视频状态点之间的图像变化
  • 随心所欲绘制曲线,比如:

在这里插入图片描述

在这里插入图片描述


一阶贝塞尔(bezier)曲线

在这里插入图片描述

如上, P 0 P_0 P0 P 1 P_1 P1 两点构成了一条线段,而我们可以通过一个函数——线性插值(lerp),来根据一个 t t t 值( t ∈ [ 0 , 1 ] t \in [0,1] t[0,1] 得到线段上一点 P P P(图中一直在滑动的点)。而 P P P 的运动轨迹(红线),便是一阶贝塞尔线段(曲线)。线性插值的数学形式(一阶贝塞尔曲线公式)为:

P = l e r p ( P 0 , P 1 , t ) = ( 1 − t ) P 0 + t P 1 P=lerp(P_0,P_1,t)=(1-t)P_0 + tP_1 P=lerp(P0P1t)=(1t)P0+tP1

一阶贝塞尔曲线有两个端点 P 0 P_0 P0 P 1 P_1 P1 ),0个控制点


二阶贝塞尔(bezier)曲线

在这里插入图片描述

如上,假设现在有点 P 2 P_2 P2 ,它与 P 1 P_1 P1 构成了新的线段,我们得到两个 一阶插值点( Q 1 Q_1 Q1 Q 2 Q_2 Q2,它们构成了绿色线段,值得注意的是,两个插值点具有相同的 t t t 值。

而此时我们在绿色线段上生成一个 二阶插值点( P P P,并让它具有 与两个一阶插值点相同的 t t t 值。 那么该点的运动轨迹就是 二阶贝塞尔曲线。其公式推导为:

  • 绿色线段左端点的运动轨迹:

Q 1 = ( 1 − t ) P 0 + t P 1 Q_1 = (1-t)P_0 + tP_1 Q1=(1t)P0+tP1

  • 绿色线段右端点的运动轨迹:

Q 2 = ( 1 − t ) P 1 + t P 2 Q_2 = (1-t)P_1 + tP_2 Q2=(1t)P1+tP2

  • 二阶贝塞尔曲线公式:

P = ( 1 − t ) Q 1 + t Q 2 P = (1-t)Q_1 + tQ_2 P=(1t)Q1+tQ2
= ( 1 − t ) ( ( 1 − t ) P 0 + t P 1 ) + t ( ( 1 − t ) P 1 + t P 2 ) =(1-t)((1-t)P_0 + tP_1) + t((1-t)P_1 + tP_2) =(1t)((1t)P0+tP1)+t((1t)P1+tP2)
= ( 1 − t ) 2 P 0 + 2 t ( t − 1 ) P 1 + t 2 P 2 =(1-t)^2P_0+2t(t-1)P_1+t^2P_2 =(1t)2P0+2t(t1)P1+t2P2

二阶贝塞尔曲线有两个端点 P 0 P_0 P0 P 2 P_2 P2),一个控制点 P 1 P_1 P1)。


三阶贝塞尔(bezier)曲线

在这里插入图片描述

经过对一阶、二阶贝塞尔曲线的研究学习,我们能知道贝塞尔曲线通过在两点之间再采点的方式实现降阶,每一次选点都是一次的降阶。

  • P 0 P_0 P0 P 1 P_1 P1 P 2 P_2 P2 P 3 P_3 P3 通过生成插值点 Q 1 Q_1 Q1 Q 2 Q_2 Q2 Q 3 Q_3 Q3 来构成二阶贝塞尔(绿色线段)
  • 在此基础上生成插值点 O 1 O_1 O1 O 2 O_2 O2 来构成一阶贝塞尔(蓝色线段)
  • 之后以 O 1 O_1 O1 O 2 O_2 O2 上的插值点 P P P 的运动轨迹来生成三阶贝塞尔曲线。

公式推导过程同二阶贝塞尔曲线,因此不做赘述,直接贴出公式:

P = ( 1 − t ) 3 P 0 + 3 t ( 1 − t ) 2 P 1 + 3 t 2 ( 1 − t ) P 2 + t 3 P 3 P=(1-t)^3P_0+3t(1-t)^2P_1+3t^2(1-t)P_2+t^3P_3 P=(1t)3P0+3t(1t)2P1+3t2(1t)P2+t3P3

三阶贝塞尔曲线有两个端点 P 0 P_0 P0 P 3 P_3 P3),两个控制点 P 1 P_1 P1 P 2 P_2 P2)。


高阶贝塞尔(bezier)曲线

  • 四阶贝塞尔曲线示意图:

在这里插入图片描述

  • 五阶贝塞尔曲线示意图:

在这里插入图片描述

  • 高阶贝塞尔曲线公式:

P ( t ) = ∑ i = 0 n P i B i , n ( t ) , t ∈ [ 0 , 1 ] P(t)=\sum_{i=0}^{n}P_iB_{i,n}(t),t \in [0,1] P(t)=i=0nPiBi,n(t)t[0,1]

B i , n ( t ) = C n i t i ( 1 − t ) n − i = n ! i ! ( n − i ) ! t i ( 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(1t)ni=i!(ni)!n!ti(1t)ni,【i=0,1,...,n


三阶贝塞尔曲线求插值(Slerp)

在熟悉了贝塞尔曲线的相关概念之后,我们来了解一下它的具体应用。通常它的应用场景是:

已知两个端点和两个控制点的情况下,根据 动画进度向量 P x P_x Px t t t,再由 t t t 确认的曲线求 P y P_y Py

回顾一下三阶贝塞尔曲线公式:
P = ( 1 − t ) 3 P 0 + 3 t ( 1 − t ) 2 P 1 + 3 t 2 ( 1 − t ) P 2 + t 3 P 3 P=(1-t)^3P_0+3t(1-t)^2P_1+3t^2(1-t)P_2+t^3P_3 P=(1t)3P0+3t(1t)2P1+3t2(1t)P2+t3P3

公式中的 P 0 P_0 P0 P 1 P_1 P1 等都是二维向量,由两个一维向量 P x P_x Px P y P_y Py 构成。而我们根据 t t t P P P,本质上是根据 t t t 来求一个坐标 ( x , y ) (x,y) (x,y)。因此,可将公式拆解在两个一维向量上:
y = ( 1 − t ) 3 P y 0 + 3 t ( 1 − t ) 2 P y 1 + 3 t 2 ( 1 − t ) P y 2 + t 3 P y 3 y=(1-t)^3P_{y0}+3t(1-t)^2P_{y1}+3t^2(1-t)P_{y2}+t^3P_{y3} y=(1t)3Py0+3t(1t)2Py1+3t2(1t)Py2+t3Py3

x = ( 1 − t ) 3 P x 0 + 3 t ( 1 − t ) 2 P x 1 + 3 t 2 ( 1 − t ) P x 2 + t 3 P x 3 x=(1-t)^3P_{x0}+3t(1-t)^2P_{x1}+3t^2(1-t)P_{x2}+t^3P_{x3} x=(1t)3Px0+3t(1t)2Px1+3t2(1t)Px2+t3Px3

而由于我们在处理动画时通常起点 P 0 P_0 P0 和终点 P 3 P_3 P3 都是可以确定的【 P 0 ( 0 , 0 ) 、 P 3 ( 1 , 1 ) P_0(0,0)、P_3(1,1) P0(0,0)P3(1,1)】,因此上述公式可以化简为(以 x x x 举例, y y y 同理):

x = 3 t ( 1 − t ) 2 P y 1 + 3 t 2 ( 1 − t ) P y 2 + t 3 x=3t(1-t)^2P_{y1}+3t^2(1-t)P_{y2}+t^3 x=3t(1t)2Py1+3t2(1t)Py2+t3

完全展开:
= 3 P y 1 t − 6 P y 1 t 2 + 3 P y 1 t 3 + 3 P y 2 t 2 − 3 P y 2 t 3 + t 3 =3P_{y1}t-6P_{y1}t^2+3P_{y1}t^3+3P_{y2}t^2-3P_{y2}t^3+t^3 =3Py1t6Py1t2+3Py1t3+3Py2t23Py2t3+t3

提取三次方系数 a a a
a = 3 P y 1 − 3 P y 2 + 1 a=3P_{y1}-3P_{y2}+1 a=3Py13Py2+1

提取二次方系数 b b b
b = 3 P y 2 − 6 P y 1 b=3P_{y2}-6P_{y1} b=3Py26Py1

提取一次方系数 c c c
c = 3 P y 1 c=3P_{y1} c=3Py1

将公式简化为:
x = a t 3 + b t 2 + c t x=at^3+bt^2+ct x=at3+bt2+ct

移动 x x x,将公式变为一元三次方程:
a t 3 + b t 2 + c t − x = 0 at^3+bt^2+ct-x=0 at3+bt2+ctx=0

此时,就可以通过卡尔丹公式根据 x x x 求出来 t t t。之后根据 t t t 可以求得 y y y
y = ( 1 − t ) 3 P y 0 + 3 t ( 1 − t ) 2 P y 1 + 3 t 2 ( 1 − t ) P y 2 + t 3 P y 3 y=(1-t)^3P_{y0}+3t(1-t)^2P_{y1}+3t^2(1-t)P_{y2}+t^3P_{y3} y=(1t)3Py0+3t(1t)2Py1+3t2(1t)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 − x d=0-x d=0x 的形式传值的, d = 0 d=0 d=0 代表 x = 0 x=0 x=0,此时曲线位于起点,t 的值可以确定,无需通过解方程获得,即 t = 0 t=0 t=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;
}

上面代码中用到的知识:

  • 一元三次方程判别式:

△ = q 2 4 + p 2 27 △ = \frac{q^2}{4} + \frac{p^2}{27} =4q2+27p2

  • 标准型方程中卡尔丹公式的一个实根:

在这里插入图片描述


http://chatgpt.dhexx.cn/article/LV7USuAm.shtml

相关文章

贝塞尔曲线(Bezier Curve)原理、公式推导及matlab代码实现

1. 定义 贝塞尔曲线(Bezier curve)&#xff0c;又称贝兹曲线或贝济埃曲线&#xff0c;是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线&#xff0c;贝兹曲线由线段与节点组成&#xff0c;节点是可拖动的支点&#xff0c;线段像可伸缩的皮筋&#…

Bezier(贝塞尔曲线通用规律算法-DEMO)

之前也看过一些相关贝塞尔曲线的知识&#xff0c;但就是一直没有实践应用&#xff1b; 今天&#xff0c;听到有同事&#xff1a;程序、美术&#xff0c;在讨论相关的&#xff0c;人物的曲线路径行走的问题&#xff1b; 一些数学比较牛X的&#xff0c;说了用2阶&#xff0c;或…

bezier曲线原理(简单阐述)

原理和简单推导&#xff08;以三阶为例&#xff09;&#xff1a; 设P0、P02、P2是一条抛物线上顺序三个不同的点。过P0和P2点的两切线交于P1点&#xff0c;在P02点的切线交P0P1和P2P1于P01和P11&#xff0c;则如下比例成立&#xff1a; 这是所谓抛物线的三切线定理。 当P0&…

Bezier贝塞尔曲线

1.简介 Bezier曲线在图形学和游戏中经常使用&#xff0c;一般用的比较多的是4个控制点的贝塞尔曲线&#xff0c;这里手写了一个仅供参考&#xff08;注&#xff1a;理论上也可以写任意多个点&#xff08;3个及以上&#xff09;的贝塞尔&#xff0c;就是一个递归的过程&#xff…

java 贝塞尔曲线_在Java中绘制贝塞尔曲线

我需要创建一个简单的Java程序,通过任意数量的点逐个像素地绘制贝塞尔曲线.此刻,一切似乎都没问题,只是曲线总是在x 0 y 0坐标处结束. 截图1 截图2 我需要它在最后一点结束.我的大脑今天工作不太好,所以我正在寻求帮助. 这是我有的&#xff1a; private void drawScene(){ pr…

贝塞尔曲线(Bezier Curve)原理及公式推导

1. 定义 贝塞尔曲线(Bezier curve)&#xff0c;又称贝兹曲线或贝济埃曲线&#xff0c;是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线&#xff0c;贝兹曲线由线段与节点组成&#xff0c;节点是可拖动的支点&#xff0c;线段像可伸缩的皮筋&#…

Bezier(贝塞尔)曲线小总结

在初学时&#xff0c;我发现Bezier曲线&#xff08;中文名贝塞尔曲线&#xff0c;想要了解历史发展等的可以看此百度百科&#xff1a;贝塞尔曲线_百度百科&#xff09;很难理解&#xff0c;故在此写了一篇自己的心得感悟。要理解它最重要的是理解Bernstein基函数。首先&#xf…

Bezier曲线原理—动态解释

Bezier曲线原理 贝塞尔曲线(Bzier curve)&#xff0c;又称贝兹曲线或贝济埃曲线&#xff0c;是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线&#xff0c;贝兹曲线由线段与节点组成&#xff0c;节点是可拖动的支点&#xff0c;线段像可伸缩的皮…

正确的Bezier曲线的绘制

原文地址:http://blog.csdn.net/mylovestart/article/details/8434310 Bezier曲线是参数多项式曲线,它由一组控制多边形折线(控制多边形)的顶点唯一定义,在控制多边形的各顶点中,只有第一个和最后一个顶点在曲线上,其他的顶点则用以定义曲线的导数,阶次和形状 Bezier曲线的数…

根据Bezier曲线的定义公式实现Bezier曲线的绘制

Bezier曲线的定义公式 Pi是曲线上点的坐标&#xff08;x,y,(z0)&#xff09;&#xff0c; Bi,n(t)伯恩斯坦公式&#xff0c;绘制Bezier曲线的第一种方法是根据这个公式来绘制。首先看看绘制的效果&#xff1a; &#xff08;1&#xff09;计算定义中多项式的值 首先要求伯恩斯…

Bezier曲线描述

Bezier曲线 1.Bezier曲线的定义 当用曲线段拟合曲线f(x)时&#xff0c;可以把曲线表示为许多小线段φi(x)之和&#xff0c;其中φi(x)称为基&#xff08;混合&#xff09;函数。 这些基&#xff08;混合&#xff09;函数是要用于计算和显示的。因此&#xff0c;经常选择多项式…

Bezier曲线的绘制

Bezier曲线是参数多项式曲线,它由一组控制多边形折线(控制多边形)的顶点唯一定义,在控制多边形的各顶点中,只有第一个和最后一个顶点在曲线上,其他的顶点则用以定义曲线的导数,阶次和形状 Bezier曲线的数学基础是能够在第一个和最后一个顶点之间进行插值的一个多项式混合函数,…

Bezier曲线的生成算法

Bezier曲线的生成方法 生成一条Bezier曲线实际上就是要求出曲线上的点。 1.根据定义直接生成Bezier曲线 定义&#xff1a; 其中 那么生成步骤为&#xff1a; ①首先给出 的递归计算式&#xff1a; ②&#xff1a;将表示成分量形式 由于的计算量大&#xff0c;算法效率不高…

bezier曲线解析与代码(c++)

前言&#xff1a; 作为rhino重度用户&#xff0c;我对于nurbs建模早有耳闻&#xff0c;但对于何为nurbs却不得其解。最近借上《计算机辅助设计》课程的机会&#xff0c;对此作了一些深入的学习&#xff0c;于是在此记录一下一些课程笔记和课后思考。了解nurbs&#xff0c;主要对…

Bezier曲线构造

Bezier曲线构造 曲线公式 曲 线 &#xff1a; C ( u ) ∑ i 0 n B n , i ( u ) P i 基 函 数 &#xff1a; B n , i n ! i ! ( n − i ) ! u i ( 1 − u ) n − i 曲线&#xff1a;C(u) \sum^n_{i0}B_{n,i}(u)P_i\\ 基函数&#xff1a;B_{n,i}\frac{n!}{i!(n-i)!}u^i(1-u)…

java版 贝塞尔曲线算法

public void test() {CvPoint controlPoint[] new CvPoint[4];controlPoint[0] new CvPoint(50, 60); //起点controlPoint[1] new CvPoint(130, 200); //控制点controlPoint[2] new CvPoint(300, 360); //控制点controlPoint[3] new CvPoint(400, 600); //终点int n cont…

Bezier曲线原理及实现代码(c++)

http://devres.zoomquiet.io/data/20110728232822/index.html Bezier曲线原理及实现代码&#xff08;c&#xff09; 一、原理&#xff1a; 贝塞尔曲线于1962年&#xff0c;由法国工程师皮埃尔贝塞尔&#xff08;Pierre Bzier&#xff09;所广泛发表&#xff0c;他运用贝塞尔曲线…

用Java实现可交互的贝塞尔曲线(Bezier curve)

关于贝塞尔曲线的详细数学原理及公式可参考&#xff1a; 贝塞尔曲线_百度百科 我们来谈谈贝塞尔曲线 本文给出了一种用Java实现贝塞尔曲线的方法&#xff0c;并且可以用鼠标拖动改变锚点。 效果演示图&#xff1a; 这里引用百度百科给出的公式&#xff1a; 二次方公式 三次方…

Bezier曲线简介

Bezier曲线简介 Bezier曲线&#xff0c;又有人叫贝赛尔曲线&#xff0c;贝兹曲线&#xff0c;在计算机绘图中经常被用到&#xff0c;由于前些天事件要用到这个&#xff0c;所以就研究了下。 有了参考资料&#xff0c;其实也不是很复杂。 曲线的介绍&#xff08;转自维基百科,见…

Bezier曲线原理及其代码实现

Bezier曲线原理及实现代码&#xff08;c&#xff09; 一、原理&#xff1a; 贝塞尔曲线于1962年&#xff0c;由法国工程师皮埃尔?贝塞尔&#xff08;Pierre B?zier&#xff09;所广泛发表&#xff0c;他运用贝塞尔曲线来为汽车的主体进行设计。贝塞尔曲线最初由 Paul de Cast…