04-Bézier曲线(1)
文章目录
本文属于 “NURBS学习笔记” 专栏,更多文章可以点击↓↓↓
NURBS学习笔记专栏
如果你经历过Win9X、Win XP的时代,一定在屏幕保护程序里见到过一个名为”Bézier曲线“的屏保,一簇封闭的曲线在屏幕里随机变换,以避免固定的系统画面长久停留在阴极射线管屏幕上,从而对屏幕造成物理的烙印损伤。这或许是我们第一次听闻Bézier大名。通过本节内容,我们也可以很容易模拟一款自己的“Bézier曲线”屏保。
这款经典的屏保程序也可以通过这个网站下载。
许多领域都会涉及到Bézier曲线:艺术设计、图形学、建筑学、前端等等,网络上可供参考的资料也非常多,一些数学软件和计算库都会将Bézier曲线的相关接口。在进入本节主题之前很有必要分享一些关于Bézier学习的有用材料,这些材料的创作者提供了比本博文更好、更全面、更具交互性的方式讲解Bézier,读者可以参考。
- Pomax Bézier曲线入门
- Richard Ekwonye Bézier Curves
- Wolfram Demonstrations Project 一些Bezier相关的演示
- Wiki Bézier curve
- 尼古拉斯 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=0∑nPiBi,n(u)0≤u≤1Bi,n(u)=i!(n−i)!n!ui(1−u)n−i(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)=1−u0≤u≤1(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)=u0≤u≤1(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)=(1−u)P0+uP10≤u≤1(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)=P1−P0 ,即曲线前进的速度方向和大小恒为定值。曲线在 1 s 1s 1s ( u u u 的取值从 0 0 0 到 1 1 1)以匀速 P 1 − P 0 \mathbf{P}_1-\mathbf{P}_0 P1−P0 从 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)=(1−u)20≤u≤1(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(1−u)0≤u≤1(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)=u20≤u≤1(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)=(1−u)2P0+2u(1−u)P1+u2P20≤u≤1(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(1−u)P0+(2−4u)P1+2uP2(9)
则有 C ′ ( 0 ) = 2 ( P 1 − P 0 ) \mathbf{C}'(0)=2(\mathbf{P}_1-\mathbf{P}_0) C′(0)=2(P1−P0) 和 C ′ ( 1 ) = 2 ( P 2 − P 1 ) \mathbf{C}'(1)=2(\mathbf{P}_2-\mathbf{P}_1) C′(1)=2(P2−P1) ,即端点处的切矢方向平行于 P 1 − P 0 \mathbf{P}_1-\mathbf{P}_0 P1−P0 和 P 2 − P 1 \mathbf{P}_2-\mathbf{P}_1 P2−P1 。 如果再求二阶导呢?可以有:
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)=2P0−4P1+2P2=2[(P2−P1)−(P1−P0)](10)
二阶导矢是一个定值,即给定了一个曲线速度的恒定的变化方向和变化量。将上述涉及到的所有点和矢量绘制在如下所示的图中,则我们可以得出这样一个认识:当 2 2 2 次Bézier曲线的控制多边形给定后,我们可以通过曲线与首末端点重合,其首末速度平行于 P 1 − P 0 \mathbf{P}_1-\mathbf{P}_0 P1−P0 和 P 2 − P 1 \mathbf{P}_2-\mathbf{P}_1 P2−P1 ,其速度变化方向为 ( P 2 − P 1 ) − ( P 1 − P 0 ) (\mathbf{P}_2 -\mathbf{P}_1)-(\mathbf{P}_1 - \mathbf{P}_0) (P2−P1)−(P1−P0) 这三个条件大致绘出曲线形状。
此外,从图中也可以进一步确认非负、规范、凸包三个性质。
接下来这段证明需要有一些解析几何里二次曲线的基础,证明过程是以具体的算例给出的,对此处不感兴趣的读者可以跳过。
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 AC−B2=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)=(1−u)2
000
+2u(1−u)
110
+u2
111
=
2u−u22u−u2u2
,0≤u≤1(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||}
∣∣P1−P0∣∣P1−P0 ,另一个垂直于该轴,且在三点确定的平面内即可。这两个轴的基为
(
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=
2u−u22u−u2u2
−P0
⋅
22220
=22u−2u2,0≤u≤1(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= 2u−u22u−u2u2 −P0 ⋅ 001 =u2,0≤u≤1(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=22y−y(x+y)2=8yx2+2xy+y2−8y=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
AC−B2=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
11011−40−40
=−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)=(1−u)30≤u≤1(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(1−u)20≤u≤1(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(1−u)0≤u≤1(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)=u30≤u≤1(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)=(1−u)3P0+3u(1−u)2P1+3u2(1−u)P2+u3P3,0≤u≤1(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(1−u)2P0+3(1−u)(1−3u)P1+3u(2−3u)P2+3u2P3,0≤u≤1(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(1−u)P0−6(2−3u)P1+6(1−3u)P2+6uP3,0≤u≤1(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+18P1−18P2+6P3,0≤u≤1(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(P1−P0)C′(1)=3(P3−P2)C′′(0)=6[(P2−P1)−(P1−P0)]C′′(1)=6[(P3−P2)−(P2−P1)](23)
将上述涉及到的所有点和矢量绘制在如下所示的图中,则我们可以得出这样一个认识:当 3 3 3 次Bézier曲线的控制多边形给定后,我们可以通过曲线与首末端点重合,其首末速度平行于 P 1 − P 0 \mathbf{P}_1-\mathbf{P}_0 P1−P0 和 P 3 − P 2 \mathbf{P}_3-\mathbf{P}_2 P3−P2 ,起始点处速度变化方向为 ( P 2 − P 1 ) − ( P 1 − P 0 ) (\mathbf{P}_2 -\mathbf{P}_1)-(\mathbf{P}_1 - \mathbf{P}_0) (P2−P1)−(P1−P0) ,终止点处速度变化方向为 ( P 3 − P 2 ) − ( P 2 − P 1 ) (\mathbf{P}_3 -\mathbf{P}_2)-(\mathbf{P}_2 - \mathbf{P}_1) (P3−P2)−(P2−P1) 这四个条件大致绘出曲线形状。
在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(P1−P0) 和 n ( P n − P n − 1 ) n(\mathbf{P}_n-\mathbf{P}_{n-1}) n(Pn−Pn−1) 这些性质在高次的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
P1−P0 和
P
n
−
P
n
−
1
\mathbf{P}_n-\mathbf{P}_{n-1}
Pn−Pn−1 ,则可再令
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(P1−P0)=Pn−Pn−1,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}
{PnPn−1=P0=Pn−k(P1−P0)=(1+k)P0−kP1,k>0(24)
即为了实现封闭的光滑性,我们损失了最后两个控制点的自由度,而
P
0
,
P
1
,
.
.
.
,
P
n
−
2
\mathbf{P}_0,\mathbf{P}_1,...,\mathbf{P}_{n-2}
P0,P1,...,Pn−2 都可以随意指定。满足上式的封闭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,...,Pn−2 给定后,符合光滑封闭要求的 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(P1−P0)=n(Pn−Pn−1)=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 P1−P0 与 P 4 − P 3 \mathbf{P}_4-\mathbf{P}_3 P4−P3 同向。
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曲线动态变化。
首先我们需要解决连续性的问题:
-
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 连续的了;
-
给定 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 Pn−1S=(1+k)P0S−kP1S , 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 Pn−1E=(1+k)P0E−kP1E ,但是这样做的 P n − 1 S , P n − 1 E \mathbf{P}_{n-1}^S,\mathbf{P}_{n-1}^E Pn−1S,Pn−1E 有可能会超出显示区域(上图所示 P n − 1 E \mathbf{P}_{n-1}^E Pn−1E 即超出了),如果超出,我们只要沿着 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 Pn−1S,Pn−1E 到显示区域边界上即可,即
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} Pn−1S=(1+kS)P0S−kSP1S,Pn−1E=(1+kE)P0E−kEP1E(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),(Pn−1S,Pn−1E),(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}
Pn−1=(1−t)Pn−1S+tPn−1E=(1−t)[(1+k)P0S−kP1S]+t[(1+k)P0E−kP1E]=(1−t)(1+k)P0S−(1−t)kP1S+t(1+k)P0E−tkP1E=(1+k)[(1−t)P0S+tP0E]−k[(1−t)P1S+tP1E]=(1+k)P0−kP1(26)
然后我们让 n − 1 n-1 n−1 个点对 ( 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),...,(Pn−2S,Pn−2E) 在显示区域内沿着各自的随机方向前进,当遇到边界时,则进行反弹,如果发生反弹则也调整前进方向。每次更新 0 0 0 到 n − 2 n-2 n−2 点对后,按照上述保证 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) (Pn−1S,Pn−1E),(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中更为关注的主题还未涉及到,我们将在随后的主题中展开讲解。