04-Bézier曲线(1)

04-Bézier曲线(1)

本文属于 “NURBS学习笔记” 专栏,更多文章可以点击↓↓↓
NURBS学习笔记专栏

如果你经历过Win9X、Win XP的时代,一定在屏幕保护程序里见到过一个名为”Bézier曲线“的屏保,一簇封闭的曲线在屏幕里随机变换,以避免固定的系统画面长久停留在阴极射线管屏幕上,从而对屏幕造成物理的烙印损伤。这或许是我们第一次听闻Bézier大名。通过本节内容,我们也可以很容易模拟一款自己的“Bézier曲线”屏保。

这款经典的屏保程序也可以通过这个网站下载。
经典的Bézier曲线屏保
许多领域都会涉及到Bézier曲线:艺术设计、图形学、建筑学、前端等等,网络上可供参考的资料也非常多,一些数学软件和计算库都会将Bézier曲线的相关接口。在进入本节主题之前很有必要分享一些关于Bézier学习的有用材料,这些材料的创作者提供了比本博文更好、更全面、更具交互性的方式讲解Bézier,读者可以参考。

  1. Pomax Bézier曲线入门
  2. Richard Ekwonye Bézier Curves
  3. Wolfram Demonstrations Project 一些Bezier相关的演示
  4. Wiki Bézier curve
  5. 尼古拉斯 M. 巴利卡拉克斯等 《计算机辅助设计与制造中的外形分析》

1. Bézier曲线

在介绍幂基曲线时,我们提到幂基曲线的基不具有规范性,从而引入了Bézier曲线。
C ( u ) = ∑ i = 0 n P i B i , n ( u ) 0 ≤ u ≤ 1 B i , n ( u ) = n ! i ! ( n − i ) ! u i ( 1 − u ) n − i (1) \mathbf{C}(u)=\sum_{i=0}^{n}\mathbf{P}_iB_{i,n}(u)\quad 0\le u \le 1 \\B_{i,n}(u)=\frac{n!}{i!(n-i)!}u^i(1-u)^{n-i} \tag{1} C(u)=i=0nPiBi,n(u)0u1Bi,n(u)=i!(ni)!n!ui(1u)ni(1)
其中系数 P i \mathbf{P}_i Pi 又称为控制点,由 { P 0 , P 1 , . . . , P n } \{\mathbf{P}_0,\mathbf{P}_1,...,\mathbf{P}_n\} {P0,P1,...,Pn} 形成的多边形称为控制多边形, B i , n ( u ) B_{i,n}(u) Bi,n(u) 是Bézier曲线的基函数。

在前面的系列博客里,我们已经知道下面几条关于Bézier基函数和曲线的性质:

  • 非负性:即 B i , n ( u ) ≥ 0 \mathbf{B}_{i,n}(u)\geq 0 Bi,n(u)0,在 u u u 的定义域内,这是易得的;
  • 规范性:我们能够从理论上证明其基函数具有规范性: ∑ i = 0 n B i , n ( u ) = 1 \sum_{i=0}^{n}\mathbf{B}_{i,n}(u)=1 i=0nBi,n(u)=1 。从而如果对一条Bézier曲线施加平移旋转变化,可直接将平移旋转作用在控制点上;
  • 凸包性:这是由非负性和规范性共同推导出的性质,在幂基曲线一节里,从凸组合的角度已给出解释。即 Bézier曲线在其控制多边形的凸包内。

1.1 1次Bézier曲线

当式 ( 1 ) (1) (1) n n n 取为 1 1 1,则
B 0 , 1 ( u ) = 1 − u 0 ≤ u ≤ 1 (2) B_{0,1}(u)=1-u\quad 0\le u \le 1 \tag{2} B0,1(u)=1u0u1(2)

B 1 , 1 ( u ) = u 0 ≤ u ≤ 1 (3) B_{1,1}(u)=u\quad 0\le u \le 1 \tag{3} B1,1(u)=u0u1(3)

C ( u ) = P 0 B 0 , 1 ( u ) + P 1 B 1 , 1 ( u ) = ( 1 − u ) P 0 + u P 1 0 ≤ u ≤ 1 (4) \mathbf{C}(u)=\mathbf{P}_0B_{0,1}(u)+\mathbf{P}_1B_{1,1}(u) =(1-u)\mathbf{P}_0+u\mathbf{P}_1\quad 0\le u \le 1 \tag{4} C(u)=P0B0,1(u)+P1B1,1(u)=(1u)P0+uP10u1(4)

显然,这是一条从 P 0 \mathbf{P}_0 P0 P 1 \mathbf{P}_1 P1 的直线,并且曲线的首末端点与 P 0 \mathbf{P}_0 P0 P 1 \mathbf{P}_1 P1 重合,即 C ( 0 ) = P 0 \mathbf{C}(0)=\mathbf{P}_0 C(0)=P0 C ( 1 ) = P 1 \mathbf{C}(1)=\mathbf{P}_1 C(1)=P1 。我们还可以算出表示曲线前进速度的一阶导矢 C ′ ( u ) = P 1 − P 0 \mathbf{C}'(u)=\mathbf{P}_1-\mathbf{P}_0 C(u)=P1P0 ,即曲线前进的速度方向和大小恒为定值。曲线在 1 s 1s 1s u u u 的取值从 0 0 0 1 1 1)以匀速 P 1 − P 0 \mathbf{P}_1-\mathbf{P}_0 P1P0 P 0 \mathbf{P}_0 P0 走向了 P 1 \mathbf{P}_1 P1

1.2 2次Bézier曲线

当式 ( 1 ) (1) (1) n n n 取为 2 2 2 ,则
B 0 , 2 ( u ) = ( 1 − u ) 2 0 ≤ u ≤ 1 (5) B_{0,2}(u)=(1-u)^2\quad 0\le u \le 1 \tag{5} B0,2(u)=(1u)20u1(5)

B 1 , 2 ( u ) = 2 u ( 1 − u ) 0 ≤ u ≤ 1 (6) B_{1,2}(u)=2u(1-u)\quad 0\le u \le 1 \tag{6} B1,2(u)=2u(1u)0u1(6)

B 2 , 2 ( u ) = u 2 0 ≤ u ≤ 1 (7) B_{2,2}(u)=u^2\quad 0\le u \le 1 \tag{7} B2,2(u)=u20u1(7)

C ( u ) = P 0 B 0 , 2 ( u ) + P 1 B 1 , 2 ( u ) + P 2 B 2 , 2 ( u ) = ( 1 − u ) 2 P 0 + 2 u ( 1 − u ) P 1 + u 2 P 2 0 ≤ u ≤ 1 (8) \begin{aligned} \mathbf{C}(u) &=\mathbf{P}_0B_{0,2}(u)+\mathbf{P}_1B_{1,2}(u)+\mathbf{P}_2B_{2,2}(u) \\ &=(1-u)^2\mathbf{P}_0+2u(1-u)\mathbf{P}_1+u^2\mathbf{P}_2 \end{aligned} \quad 0\le u \le 1 \tag{8} C(u)=P0B0,2(u)+P1B1,2(u)+P2B2,2(u)=(1u)2P0+2u(1u)P1+u2P20u1(8)

此时 C ( u ) \mathbf{C}(u) C(u) 的几何意义并不明显。我们取3个点 P 0 = ( − 1 , 1 ) T \mathbf{P}_0=(-1,1)^T P0=(1,1)T , P 1 = ( 4 , 3 ) T \mathbf{P}_1=(4,3)^T P1=(4,3)T , P 2 = ( 6 , − 2 ) T \mathbf{P}_2=(6,-2)^T P2=(6,2)T,做出 2 2 2 次Bézier曲线的形成过程及结果,如下图所示。
在这里插入图片描述

这是一条从 P 0 \mathbf{P}_0 P0 P 1 \mathbf{P}_1 P1 的抛物线弧(后文将给出算例证明),并且曲线的首末端点与 P 0 \mathbf{P}_0 P0 P 1 \mathbf{P}_1 P1 重合,即 C ( 0 ) = P 0 \mathbf{C}(0)=\mathbf{P}_0 C(0)=P0 C ( 1 ) = P 1 \mathbf{C}(1)=\mathbf{P}_1 C(1)=P1 。我们还可以算出表示曲线前进速度的一阶导矢 :
C ′ ( u ) = − 2 ( 1 − u ) P 0 + ( 2 − 4 u ) P 1 + 2 u P 2 (9) \begin{aligned} \mathbf{C}'(u) &=-2(1-u)\mathbf{P}_0 +(2-4u)\mathbf{P}_1+2u\mathbf{P}_2 \end{aligned} \tag{9} C(u)=2(1u)P0+(24u)P1+2uP2(9)

则有 C ′ ( 0 ) = 2 ( P 1 − P 0 ) \mathbf{C}'(0)=2(\mathbf{P}_1-\mathbf{P}_0) C(0)=2(P1P0) C ′ ( 1 ) = 2 ( P 2 − P 1 ) \mathbf{C}'(1)=2(\mathbf{P}_2-\mathbf{P}_1) C(1)=2(P2P1) ,即端点处的切矢方向平行于 P 1 − P 0 \mathbf{P}_1-\mathbf{P}_0 P1P0 P 2 − P 1 \mathbf{P}_2-\mathbf{P}_1 P2P1 。 如果再求二阶导呢?可以有:

C ′ ′ ( u ) = 2 P 0 − 4 P 1 + 2 P 2 = 2 [ ( P 2 − P 1 ) − ( P 1 − P 0 ) ] (10) \begin{aligned} \mathbf{C}''(u) &=2\mathbf{P}_0 -4\mathbf{P}_1+2\mathbf{P}_2 \\ &=2[(\mathbf{P}_2 -\mathbf{P}_1)-(\mathbf{P}_1 - \mathbf{P}_0)] \end{aligned} \tag{10} C′′(u)=2P04P1+2P2=2[(P2P1)(P1P0)](10)

二阶导矢是一个定值,即给定了一个曲线速度的恒定的变化方向和变化量。将上述涉及到的所有点和矢量绘制在如下所示的图中,则我们可以得出这样一个认识:当 2 2 2 次Bézier曲线的控制多边形给定后,我们可以通过曲线与首末端点重合,其首末速度平行于 P 1 − P 0 \mathbf{P}_1-\mathbf{P}_0 P1P0 P 2 − P 1 \mathbf{P}_2-\mathbf{P}_1 P2P1 ,其速度变化方向为 ( P 2 − P 1 ) − ( P 1 − P 0 ) (\mathbf{P}_2 -\mathbf{P}_1)-(\mathbf{P}_1 - \mathbf{P}_0) (P2P1)(P1P0) 这三个条件大致绘出曲线形状。

在这里插入图片描述

此外,从图中也可以进一步确认非负、规范、凸包三个性质。

接下来这段证明需要有一些解析几何二次曲线的基础,证明过程是以具体的算例给出的,对此处不感兴趣的读者可以跳过。

1.2.1 2次Bézier曲线是抛物线弧的证明

首先给出解析几何里的结论:二次曲线方程有标准形式 A x 2 + 2 B x y + C y 2 + 2 D x + 2 E y + F = 0 Ax^2+2Bxy+Cy^2+2Dx+2Ey+F=0 Ax2+2Bxy+Cy2+2Dx+2Ey+F=0 ,则当 A C − B 2 = 0 AC-B^2=0 ACB2=0 且曲线不退化,即 d e t ( A B D B C E D E F ) ≠ 0 det\begin{pmatrix}A & B & D \\ B & C & E \\ D & E & F \end{pmatrix} \neq 0 det ABDBCEDEF =0时,二次曲线为抛物线

P 0 = ( 0 , 0 , 0 ) T \mathbf{P}_0=(0,0,0)^T P0=(0,0,0)T , P 1 = ( 1 , 1 , 0 ) T \mathbf{P}_1=(1,1,0)^T P1=(1,1,0)T , P 2 = ( 1 , 1 , 1 ) T \mathbf{P}_2=(1,1,1)^T P2=(1,1,1)T ,则
C ( u ) = ( 1 − u ) 2 ( 0 0 0 ) + 2 u ( 1 − u ) ( 1 1 0 ) + u 2 ( 1 1 1 ) = ( 2 u − u 2 2 u − u 2 u 2 ) , 0 ≤ u ≤ 1 (11) \begin{aligned} \mathbf{C}(u) &=(1-u)^2\begin{pmatrix}0\\0\\0\end{pmatrix} +2u(1-u)\begin{pmatrix}1\\1\\0\end{pmatrix} +u^2\begin{pmatrix}1\\1\\1\end{pmatrix} \\ &=\begin{pmatrix}2u-u^2\\2u-u^2\\u^2\end{pmatrix} \end{aligned} ,\quad 0\le u \le 1 \tag{11} C(u)=(1u)2 000 +2u(1u) 110 +u2 111 = 2uu22uu2u2 ,0u1(11)
C ( u ) \mathbf{C}(u) C(u) 本就可以看做是 P 0 , P 1 , P 2 \mathbf{P}_0,\mathbf{P}_1,\mathbf{P}_2 P0,P1,P2 三点的线性组合,其一定在这三点确定的平面内。我们在该平面内寻找一个坐标系,其原点即为 P 0 \mathbf{P}_0 P0 ,其中一个轴为 P 1 − P 0 ∣ ∣ P 1 − P 0 ∣ ∣ \frac{\mathbf{P}_1-\mathbf{P}_0}{||\mathbf{P}_1-\mathbf{P}_0||} ∣∣P1P0∣∣P1P0 ,另一个垂直于该轴,且在三点确定的平面内即可。这两个轴的基为 ( 2 2 , 2 2 , 0 ) T (\frac{\sqrt{2}}{2},\frac{\sqrt{2}}{2},0)^T (22 ,22 ,0)T ( 0 , 0 , 1 ) T (0,0,1)^T (0,0,1)T ,将曲线 C ( u ) \mathbf{C}(u) C(u) 变换到这个平面内的坐标系,即得其中一个坐标为
x = [ ( 2 u − u 2 2 u − u 2 u 2 ) − P 0 ] ⋅ ( 2 2 2 2 0 ) = 2 2 u − 2 u 2 , 0 ≤ u ≤ 1 (12) \begin{aligned} x &= \left[ \begin{pmatrix}2u-u^2\\2u-u^2\\u^2\end{pmatrix} - \mathbf{P}_0 \right] \cdot \begin{pmatrix} \frac{\sqrt{2}}{2} \\ \frac{\sqrt{2}}{2} \\ 0 \end{pmatrix} \\ &= 2\sqrt{2}u-\sqrt{2}u^2 \end{aligned} ,\quad 0\le u \le 1 \tag{12} x= 2uu22uu2u2 P0 22 22 0 =22 u2 u2,0u1(12)

y = [ ( 2 u − u 2 2 u − u 2 u 2 ) − P 0 ] ⋅ ( 0 0 1 ) = u 2 , 0 ≤ u ≤ 1 (13) \begin{aligned} y &= \left[ \begin{pmatrix}2u-u^2\\2u-u^2\\u^2\end{pmatrix} - \mathbf{P}_0 \right] \cdot \begin{pmatrix} 0 \\ 0 \\ 1 \end{pmatrix} \\ &= u^2 \end{aligned} ,\quad 0\le u \le 1 \tag{13} y= 2uu22uu2u2 P0 001 =u2,0u1(13)


x = 2 2 y − y ( x + y ) 2 = 8 y x 2 + 2 x y + y 2 − 8 y = 0 (14) x=2\sqrt{2}\sqrt{y}-y \\ (x+y)^2=8y \\ x^2+2xy+y^2-8y=0 \tag{14} x=22 y y(x+y)2=8yx2+2xy+y28y=0(14)
对应到二次曲线的标准形式,则 A = 1 , B = 1 , C = 1 , D = 0 , E = − 4 , F = 0 A=1,B=1,C=1,D=0,E=-4,F=0 A=1,B=1,C=1,D=0,E=4,F=0 ,此时 A C − B 2 = 0 AC-B^2=0 ACB2=0 d e t ( A B D B C E D E F ) = d e t ( 1 1 0 1 1 − 4 0 − 4 0 ) = − 16 ≠ 0 det\begin{pmatrix}A & B & D \\ B & C & E \\ D & E & F \end{pmatrix} = det\begin{pmatrix}1 & 1 & 0 \\ 1 & 1 & -4 \\ 0 & -4 & 0 \end{pmatrix} =-16\neq 0 det ABDBCEDEF =det 110114040 =16=0 ,所以曲线是抛物线。更严格符号证明读者可参考该例做出。

1.3 3次Bézier曲线

当式 ( 1 ) (1) (1) n n n 取为3,则
B 0 , 3 ( u ) = ( 1 − u ) 3 0 ≤ u ≤ 1 (15) B_{0,3}(u)=(1-u)^3 \quad 0\le u \le 1 \tag{15} B0,3(u)=(1u)30u1(15)

B 1 , 3 ( u ) = 3 u ( 1 − u ) 2 0 ≤ u ≤ 1 (16) B_{1,3}(u)=3u(1-u)^2 \quad 0\le u \le 1 \tag{16} B1,3(u)=3u(1u)20u1(16)

B 2 , 3 ( u ) = 3 u 2 ( 1 − u ) 0 ≤ u ≤ 1 (17) B_{2,3}(u)=3u^2(1-u) \quad 0\le u \le 1 \tag{17} B2,3(u)=3u2(1u)0u1(17)

B 3 , 3 ( u ) = u 3 0 ≤ u ≤ 1 (18) B_{3,3}(u)=u^3 \quad 0\le u \le 1 \tag{18} B3,3(u)=u30u1(18)

C ( u ) = P 0 B 0 , 3 ( u ) + P 1 B 1 , 3 ( u ) + P 2 B 2 , 3 ( u ) + P 3 B 3 , 3 ( u ) = ( 1 − u ) 3 P 0 + 3 u ( 1 − u ) 2 P 1 + 3 u 2 ( 1 − u ) P 2 + u 3 P 3 , 0 ≤ u ≤ 1 (19) \begin{aligned} \mathbf{C}(u) &= \mathbf{P}_0B_{0,3}(u) + \mathbf{P}_1B_{1,3}(u) + \mathbf{P}_2B_{2,3}(u) + \mathbf{P}_3B_{3,3}(u) \\ &= (1-u)^3\mathbf{P}_0 + 3u(1-u)^2\mathbf{P}_1 + 3u^2(1-u)\mathbf{P}_2 + u^3\mathbf{P}_3 \end{aligned} ,\quad 0\le u \le 1 \tag{19} C(u)=P0B0,3(u)+P1B1,3(u)+P2B2,3(u)+P3B3,3(u)=(1u)3P0+3u(1u)2P1+3u2(1u)P2+u3P3,0u1(19)

我们取 4 4 4 个点 P 0 = ( 4 , 3 ) T \mathbf{P}_0=(4,3)^T P0=(4,3)T , P 1 = ( 6 , 2 ) T \mathbf{P}_1=(6,2)^T P1=(6,2)T , P 2 = ( 3 , 0 ) T \mathbf{P}_2=(3,0)^T P2=(3,0)T P 3 = ( 2 , 4 ) T \mathbf{P}_3=(2,4)^T P3=(2,4)T 做出 3 3 3 次Bézier曲线的形成过程及结果,如下图所示。

在这里插入图片描述

我们同样可以验证 C ( 0 ) = P 0 \mathbf{C}(0)=\mathbf{P}_0 C(0)=P0 C ( 1 ) = P 1 \mathbf{C}(1)=\mathbf{P}_1 C(1)=P1 ,对非负、规范、凸包三性质从图中也可以看出。我们也来验证下 3 3 3 次Bézier曲线的一、二、三阶导矢:
C ′ ( u ) = − 3 ( 1 − u ) 2 P 0 + 3 ( 1 − u ) ( 1 − 3 u ) P 1 + 3 u ( 2 − 3 u ) P 2 + 3 u 2 P 3 , 0 ≤ u ≤ 1 (20) \mathbf{C}'(u) = -3(1-u)^2\mathbf{P}_0 + 3(1-u)(1-3u)\mathbf{P}_1 + 3u(2-3u)\mathbf{P}_2 + 3u^2\mathbf{P}_3 ,\quad 0\le u \le 1 \tag{20} C(u)=3(1u)2P0+3(1u)(13u)P1+3u(23u)P2+3u2P3,0u1(20)

C ′ ′ ( u ) = 6 ( 1 − u ) P 0 − 6 ( 2 − 3 u ) P 1 + 6 ( 1 − 3 u ) P 2 + 6 u P 3 , 0 ≤ u ≤ 1 (21) \mathbf{C}''(u) = 6(1-u)\mathbf{P}_0 -6(2-3u)\mathbf{P}_1 + 6(1-3u)\mathbf{P}_2 +6u\mathbf{P}_3 ,\quad 0\le u \le 1 \tag{21} C′′(u)=6(1u)P06(23u)P1+6(13u)P2+6uP3,0u1(21)

C 3 ( u ) = − 6 P 0 + 18 P 1 − 18 P 2 + 6 P 3 , 0 ≤ u ≤ 1 (22) \mathbf{C}^3(u) = -6\mathbf{P}_0 +18\mathbf{P}_1 -18\mathbf{P}_2 +6\mathbf{P}_3 ,\quad 0\le u \le 1 \tag{22} C3(u)=6P0+18P118P2+6P3,0u1(22)

虽然 3 3 3 次Bézier曲线的三阶导矢恒为定值,但加速度的变化量缺乏直观的几何意义,我们仅考察首末端点处的一、二阶导矢,则有

C ′ ( 0 ) = 3 ( P 1 − P 0 ) C ′ ( 1 ) = 3 ( P 3 − P 2 ) C ′ ′ ( 0 ) = 6 [ ( P 2 − P 1 ) − ( P 1 − P 0 ) ] C ′ ′ ( 1 ) = 6 [ ( P 3 − P 2 ) − ( P 2 − P 1 ) ] (23) \mathbf{C}'(0)=3(\mathbf{P}_1-\mathbf{P}_0) \\ \mathbf{C}'(1)=3(\mathbf{P}_3-\mathbf{P}_2) \\ \mathbf{C}''(0) = 6[(\mathbf{P}_2-\mathbf{P}_1)-(\mathbf{P}_1-\mathbf{P}_0)] \\ \mathbf{C}''(1) = 6[(\mathbf{P}_3-\mathbf{P}_2)-(\mathbf{P}_2-\mathbf{P}_1)] \tag{23} C(0)=3(P1P0)C(1)=3(P3P2)C′′(0)=6[(P2P1)(P1P0)]C′′(1)=6[(P3P2)(P2P1)](23)

将上述涉及到的所有点和矢量绘制在如下所示的图中,则我们可以得出这样一个认识:当 3 3 3 次Bézier曲线的控制多边形给定后,我们可以通过曲线与首末端点重合,其首末速度平行于 P 1 − P 0 \mathbf{P}_1-\mathbf{P}_0 P1P0 P 3 − P 2 \mathbf{P}_3-\mathbf{P}_2 P3P2 ,起始点处速度变化方向为 ( P 2 − P 1 ) − ( P 1 − P 0 ) (\mathbf{P}_2 -\mathbf{P}_1)-(\mathbf{P}_1 - \mathbf{P}_0) (P2P1)(P1P0) ,终止点处速度变化方向为 ( P 3 − P 2 ) − ( P 2 − P 1 ) (\mathbf{P}_3 -\mathbf{P}_2)-(\mathbf{P}_2 - \mathbf{P}_1) (P3P2)(P2P1) 这四个条件大致绘出曲线形状。

在这里插入图片描述

pomax的教程中可以交互感受不同控制多边形形成的 3 3 3 次Bézier曲线。

1.4 闭合的Bézier曲线

1 1 1 次逐渐增加到 3 3 3 次,我们已经能够感受到一些Bézier曲线不变的性质以及一些与次数有关的、暗含着递归形式的性质。非负、规范、凸包、首末端点重合、首末速度为 n ( P 1 − P 0 ) n(\mathbf{P}_1-\mathbf{P}_0) n(P1P0) n ( P n − P n − 1 ) n(\mathbf{P}_n-\mathbf{P}_{n-1}) n(PnPn1) 这些性质在高次的Bézier曲线里仍然拥有。

到目前为止,对于Bézier曲线的认识已经能够让我们模拟一套经典的”Bézier曲线屏保”了。但是在此之前还需要解决的问题是怎么创建封闭的Bézier曲线,经典的屏保程序里曲线都是封闭的。一个简单的实现想法是:既然Bézier曲线与控制多边形的首末点重合,那让控制多边形的首末点重合,整个曲线不就封闭了,如下图所示,我们仅将首末点设为一致,但这样的封闭曲线大概率会出现一个尖点,这样的曲线确实是闭合的,但在首末点处也仅仅是 G 0 \mathbf{G}_0 G0 连续( 0 0 0 阶几何连续)的。所谓曲线在某点处 G 0 \mathbf{G}_0 G0 连续,即曲线在该点处的左右两端仅仅是搭接关系,并不光滑。

在这里插入图片描述

我们可以提出更高的光滑要求,即曲线在首末点处的切矢方向也最好相同。前面我们已经知道Bézier曲线首末点处的速度同向于 P 1 − P 0 \mathbf{P}_1-\mathbf{P}_0 P1P0 P n − P n − 1 \mathbf{P}_n-\mathbf{P}_{n-1} PnPn1 ,则可再令 k ( P 1 − P 0 ) = P n − P n − 1 , k > 0 k(\mathbf{P}_1-\mathbf{P}_0) = \mathbf{P}_n-\mathbf{P}_{n-1},k>0 k(P1P0)=PnPn1,k>0 , 那么得到方程
{ P n = P 0 P n − 1 = P n − k ( P 1 − P 0 ) = ( 1 + k ) P 0 − k P 1 , k > 0 (24) \left\{\begin{matrix}\begin{aligned} \mathbf{P}_n&=\mathbf{P}_0 \\ \mathbf{P}_{n-1}&=\mathbf{P}_n-k(\mathbf{P}_1-\mathbf{P}_0)=(1+k)\mathbf{P}_0-k\mathbf{P}_1,k>0 \end{aligned}\end{matrix}\right. \tag{24} {PnPn1=P0=Pnk(P1P0)=(1+k)P0kP1,k>0(24)
即为了实现封闭的光滑性,我们损失了最后两个控制点的自由度,而 P 0 , P 1 , . . . , P n − 2 \mathbf{P}_0,\mathbf{P}_1,...,\mathbf{P}_{n-2} P0,P1,...,Pn2 都可以随意指定。满足上式的封闭Bézier曲线即称之为端点 G 1 \mathbf{G}_1 G1 连续。 推广下去的话,我们还将得到光滑性更高的封闭曲线。

在上式中, k k k 的值并未给定,意味着当 P 0 , P 1 , . . . , P n − 2 \mathbf{P}_0,\mathbf{P}_1,...,\mathbf{P}_{n-2} P0,P1,...,Pn2 给定后,符合光滑封闭要求的 n n n 次Bézier曲线有无数条,只要 k > 0 k>0 k>0 即可。在所有的 k k k 中,有一个极为特殊,能够保证 C ′ ( 0 ) = n ( P 1 − P 0 ) = n ( P n − P n − 1 ) = C ′ ( 1 ) \mathbf{C}'(0)=n(\mathbf{P}_1-\mathbf{P}_0) = n(\mathbf{P}_n-\mathbf{P}_{n-1})=\mathbf{C}'(1) C(0)=n(P1P0)=n(PnPn1)=C(1) ,此时我们称之为端点 C 1 \mathbf{C}_1 C1 连续( 1 1 1 阶参数连续)。我们设想这样一个场景:一段首尾封闭的盘山公路,汽车可以以不同的速度通过,尤其是在首末端点处,每次都需要在此处瞬时切换速度(现实场景下达不到)。汽车以不同的速度配置都能走出一个封闭的 1 1 1 阶几何连续的公路曲线,这其中,在首末端点处速度不用瞬时切换的配置所走出的路径即为 1 1 1 阶参数连续的。可见参数连续是更为严苛的,但在CAD领域,我们更关注曲线的形态,而不关注曲线是如何“描绘”出来的,所以更为强调几何连续。读者可以拓展思考下CAM领域对于连续性的要求。

我们取一个符合 G 1 \mathbf{G}_1 G1 连续要求的 4 4 4 次Bézier曲线,可见 P 1 − P 0 \mathbf{P}_1-\mathbf{P}_0 P1P0 P 4 − P 3 \mathbf{P}_4-\mathbf{P}_3 P4P3 同向。

在这里插入图片描述

2. 模拟Bézier曲线屏保

到此为止,我们就有能力创建一条具有一定光滑性的封闭的Bézier曲线了,接下来的问题就与Bézier本身没有太大关系了,即我们要生成一族封闭的Bézier曲线,且还是随时变动的。

一个思路如下图所示,我们可以在显示区域内生成 0 0 0 n n n 个随机点对 ( P 0 S , P 0 E ) , ( P 1 S , P 1 E ) , . . . , ( P n S , P n E ) (\mathbf{P}_0^S,\mathbf{P}_0^E),(\mathbf{P}_1^S,\mathbf{P}_1^E),...,(\mathbf{P}_n^S,\mathbf{P}_n^E) (P0S,P0E),(P1S,P1E),...,(PnS,PnE),然后在其上线性插入 n u m L i n e numLine numLine 个点,就可以得到 n u m L i n e numLine numLine 个 Bézier 的控制多边形了(图中5条蓝色折线段)。而后需要考虑的问题就是怎么让这些点对沿着随机方向变化,从而实现控制多边形的动态变化,进一步达到一簇封闭的Bézier曲线动态变化。

在这里插入图片描述

首先我们需要解决连续性的问题:

  1. P n S = P 0 S , P n E = P 0 E \mathbf{P}_n^S=\mathbf{P}_0^S,\mathbf{P}_n^E=\mathbf{P}_0^E PnS=P0S,PnE=P0E ,这样的话我们将来做出的曲线就满足 G 0 \mathbf{G}_0 G0 连续的了;

  2. 给定 k = 1 k=1 k=1 计算出 P n − 1 S = ( 1 + k ) P 0 S − k P 1 S \mathbf{P}_{n-1}^S=(1+k)\mathbf{P}_0^S-k\mathbf{P}_1^S Pn1S=(1+k)P0SkP1S P n − 1 E = ( 1 + k ) P 0 E − k P 1 E \mathbf{P}_{n-1}^E=(1+k)\mathbf{P}_0^E-k\mathbf{P}_1^E Pn1E=(1+k)P0EkP1E ,但是这样做的 P n − 1 S , P n − 1 E \mathbf{P}_{n-1}^S,\mathbf{P}_{n-1}^E Pn1S,Pn1E 有可能会超出显示区域(上图所示 P n − 1 E \mathbf{P}_{n-1}^E Pn1E 即超出了),如果超出,我们只要沿着 P 1 S P 0 S → \overrightarrow{\mathbf{P}_1^S\mathbf{P}_0^S} P1SP0S P 1 E P 0 E → \overrightarrow{\mathbf{P}_1^E\mathbf{P}_0^E} P1EP0E 的方向调整 P n − 1 S , P n − 1 E \mathbf{P}_{n-1}^S,\mathbf{P}_{n-1}^E Pn1S,Pn1E 到显示区域边界上即可,即

P n − 1 S = ( 1 + k S ) P 0 S − k S P 1 S , P n − 1 E = ( 1 + k E ) P 0 E − k E P 1 E (25) \mathbf{P}_{n-1}^S=(1+\color{red}{k_S}\color{black})\mathbf{P}_0^S-\color{red}k_S\color{black}\mathbf{P}_1^S,\mathbf{P}_{n-1}^E=(1+\color{red}k_E\color{black})\mathbf{P}_0^E-\color{red}k_E\color{black}\mathbf{P}_1^E \tag{25} Pn1S=(1+kS)P0SkSP1S,Pn1E=(1+kE)P0EkEP1E(25)

此时的 k S k_S kS k E k_E kE 都是比 1.0 1.0 1.0 小的数, 尽管这样,仍存在一个问题,后续当我们在点对 ( P 0 S , P 0 E ) , ( P 1 S , P 1 E ) , ( P n − 1 S , P n − 1 E ) , ( P n S , P n E ) (\mathbf{P}_0^S,\mathbf{P}_0^E),(\mathbf{P}_1^S,\mathbf{P}_1^E),(\mathbf{P}_{n-1}^S,\mathbf{P}_{n-1}^E),(\mathbf{P}_n^S,\mathbf{P}_n^E) (P0S,P0E),(P1S,P1E),(Pn1S,Pn1E),(PnS,PnE) 上线性插入控制点时,控制点不一定可以满足 G 1 \mathbf{G}_1 G1 连续的要求,我们可以令 k = k S = k E = m i n ( k S , k E ) k=k_S=k_E=min(k_S,k_E) k=kS=kE=min(kS,kE) ,此时线性插入控制点就符合连续性要求了,即
P n − 1 = ( 1 − t ) P n − 1 S + t P n − 1 E = ( 1 − t ) [ ( 1 + k ) P 0 S − k P 1 S ] + t [ ( 1 + k ) P 0 E − k P 1 E ] = ( 1 − t ) ( 1 + k ) P 0 S − ( 1 − t ) k P 1 S + t ( 1 + k ) P 0 E − t k P 1 E = ( 1 + k ) [ ( 1 − t ) P 0 S + t P 0 E ] − k [ ( 1 − t ) P 1 S + t P 1 E ] = ( 1 + k ) P 0 − k P 1 (26) \begin{aligned} \mathbf{P}_{n-1} &= (1-t)\mathbf{P}_{n-1}^S + t\mathbf{P}_{n-1}^E \\ &=(1-t)[(1+k)\mathbf{P}_0^S-k\mathbf{P}_1^S] + t[(1+k)\mathbf{P}_0^E-k\mathbf{P}_1^E] \\ &=(1-t)(1+k)\mathbf{P}_0^S-(1-t)k\mathbf{P}_1^S + t(1+k)\mathbf{P}_0^E-tk\mathbf{P}_1^E \\ &=(1+k)\color{red}\left[(1-t)\mathbf{P}_0^S + t\mathbf{P}_0^E \right] \color{black} - k\color{blue} \left[(1-t)\mathbf{P}_1^S + t\mathbf{P}_1^E \right] \color{black} \\ &=(1+k)\color{red} \mathbf{P}_0 \color{black} - k\color{blue} \mathbf{P}_1 \color{black} \end{aligned} \tag{26} Pn1=(1t)Pn1S+tPn1E=(1t)[(1+k)P0SkP1S]+t[(1+k)P0EkP1E]=(1t)(1+k)P0S(1t)kP1S+t(1+k)P0EtkP1E=(1+k)[(1t)P0S+tP0E]k[(1t)P1S+tP1E]=(1+k)P0kP1(26)

然后我们让 n − 1 n-1 n1 个点对 ( P 0 S , P 0 E ) , ( P 1 S , P 1 E ) , . . . , ( P n − 2 S , P n − 2 E ) (\mathbf{P}_0^S,\mathbf{P}_0^E),(\mathbf{P}_1^S,\mathbf{P}_1^E),...,(\mathbf{P}_{n-2}^S,\mathbf{P}_{n-2}^E) (P0S,P0E),(P1S,P1E),...,(Pn2S,Pn2E) 在显示区域内沿着各自的随机方向前进,当遇到边界时,则进行反弹,如果发生反弹则也调整前进方向。每次更新 0 0 0 n − 2 n-2 n2 点对后,按照上述保证 G 1 \mathbf{G}_1 G1 连续的方法计算出 ( P n − 1 S , P n − 1 E ) , ( P n S , P n E ) (\mathbf{P}_{n-1}^S,\mathbf{P}_{n-1}^E),(\mathbf{P}_n^S,\mathbf{P}_n^E) (Pn1S,Pn1E),(PnS,PnE) 。这样我们就得到了在显示区域内动态变化的点对,如果在每个点对上使用同一个参数线性插值,得到的Bézier曲线的控制多边形也符合 G 1 \mathbf{G}_1 G1 连续。如下图所示,我们要绘制 8 8 8 次Bézier曲线,则需要创建 9 9 9 个点对 ( P 0 S , P 0 E ) , ( P 1 S , P 1 E ) , . . . , ( P 8 S , P 8 E ) (\mathbf{P}_0^S,\mathbf{P}_0^E),(\mathbf{P}_1^S,\mathbf{P}_1^E),...,(\mathbf{P}_{8}^S,\mathbf{P}_{8}^E) (P0S,P0E),(P1S,P1E),...,(P8S,P8E) ,最后一个点对 ( P 8 S , P 8 E ) (\mathbf{P}_{8}^S,\mathbf{P}_{8}^E) (P8S,P8E) 与第一个点对 ( P 0 S , P 0 E ) (\mathbf{P}_{0}^S,\mathbf{P}_{0}^E) (P0S,P0E) 重合,倒数第二个点 ( P 8 S , P 8 E ) (\mathbf{P}_{8}^S,\mathbf{P}_{8}^E) (P8S,P8E) 对受制于连续性要求,要由 ( P 0 S , P 0 E ) , ( P 1 S , P 1 E ) (\mathbf{P}_0^S,\mathbf{P}_0^E),(\mathbf{P}_1^S,\mathbf{P}_1^E) (P0S,P0E),(P1S,P1E) 求出。我们在每一帧的点对上线性插入 40 40 40 条控制多边形,则多边形的动态效果如下。

在这里插入图片描述

拥有每一帧下Bézier曲线的控制多边形后,使用不同平台下提供的计算Bézier曲线的函数库或者仅参考公式 ( 1 ) (1) (1) 就可以求出每一个Bézier曲线的图像了。看看我们模拟的屏保程序的效果。

在这里插入图片描述

模拟屏保程序仅仅让我们初步感受Bézier曲线的几何美,实际上更为重要的高效计算曲线上的每一个点、求取曲线上每一个点的切矢、计算曲线的交点等在CAD中更为关注的主题还未涉及到,我们将在随后的主题中展开讲解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值