本讲义基于 Steve Marschner & Peter Shirley 所著《虎书》(Fundamentals of Computer Graphics)第5版第15章(p.401-446)曲线。
参数曲线与曲面的完整理论——Bézier/有理Bézier/de Casteljau/Catmull-Rom/B样条/NURBS、弧长参数化、曲率/挠率/Frenet 框架、最小二乘拟合。
本版插画采用 Guizang 材质插画风格重新绘制。
由于曲线的"笔触"无限细,它很难创建填充区域。尽管空间填充曲线理论上是可能的(通过让曲线无限多次地折叠穿过自身),但我们在这里不考虑这类数学奇观。一般来说,我们把曲线视为事物的轮廓,而不是其"内部"。
我们需要处理的核心问题是:如何指定一条曲线——如何为一条曲线赋予一个名称或表示,使得我们能够在计算机中表示它。对于某些曲线来说,命名它们是容易的,因为它们具有已知的形状:线段、圆、椭圆弧等等。一条没有"命名"形状的通用曲线有时被称为自由形态曲线(free-form curve)。因为自由形态曲线可以呈现几乎任意的形状,对它们的指定要困难得多。
有三种主要的数学曲线指定方式:
1. 隐式曲线表示(Implicit curve representation)通过给出一个能检测某点是否在曲线上的过程来定义曲线上的点集。通常,隐式曲线表示由一个如下形式的隐式函数定义:
f(x, y) = 0
因此曲线就是使该方程成立的点的集合。注意隐式函数 f 是一个标量函数(它返回单个实数)。隐式表示的优点是:可以方便地判断一个点是否在曲线上(代入计算即可),并且曲线将平面划分为 f < 0 和 f > 0 两个区域。缺点是在曲线上生成均匀采样点非常困难——需要求解非线性方程。
2. 参数曲线表示(Parametric curve representation)提供了一个从自由参数到曲线上点集的映射。也就是说,这个自由参数为曲线上的点提供了一个索引。曲线的参数形式是一个函数,它将位置赋给自由参数的值。直观地说,如果你把曲线想象成可以用笔在纸上画出的东西,那么自由参数就是时间,其范围从我们开始画曲线的时刻到画完的时刻。该曲线的参数函数告诉我们笔在任意时刻的位置:
(x, y) = f(t)
注意参数函数是一个向量值函数。这个例子是二维曲线,所以函数的输出是一个二维向量;在三维中则是一个三维向量。参数表示的优点是:给定参数值就能直接求出坐标——这在实时渲染和动画中至关重要。缺点是判断一个点是否在曲线上变得困难(需要求解非线性方程找到对应的参数值)。
生活类比:把参数曲线想象成一场赛跑的GPS轨迹记录。隐式表示就像是赛道的地图——你可以查看任何一点并判断"这是赛道内还是赛道外";参数表示就像是运动员手腕上的计时器——给定时刻t,你精确知道运动员在哪个位置。两者描述的是同一条路线,但一个适合"判断内外",另一个适合"追踪运动"。
3. 生成式或过程式曲线表示(Generative or procedural curve representation)提供能生成曲线上点的过程,这些过程不属于前两种类别。生成式曲线描述的例子包括细分格式(subdivision schemes)和分形(fractals)。
三种曲线表示的完整对比
为了更好地理解这三种表示的本质差异,下表从五个关键维度进行了系统对比:
| 维度 | 隐式表示 f(x,y)=0 | 显式表示 y=f(x) | 参数表示 (x,y)=f(t) |
|---|---|---|---|
| 定义方式 | 满足方程的点的集合,f 是标量函数 | 一个坐标用另一个坐标的函数表示,y 是 x 的函数 | 每个坐标都是独立参数 t 的函数,f 是向量值函数 |
| 优点 | ① 内外判定极快(代入即知) ② 布尔运算方便(并/交/差通过 min/max 实现) ③ 可以表示闭合/自交/多分支曲线 | ① 求值简单(代入 x 即得 y) ② 微积分分析直观 ③ 熟悉的形式(y=f(x)) | ① 轻松生成均匀采样点(递增 t 即可) ② 可表示任意多值/闭合/自交曲线 ③ 切线与法线计算简单(求导即可) ④ 适合动画与实时渲染 |
| 缺点 | ① 生成采样点极难(需解方程) ② 难以控制局部形状 ③ 设计不够直观 | ① 无法表示垂直切线 ② 无法表示闭合曲线 ③ 不能表示多值曲线(一个 x 对应多个 y) | ① 点-曲线距离计算困难 ② 判断点是否在曲线上需解非线性方程 ③ 参数化有自由度(同一条曲线有无穷多种参数化) |
| 可计算性 | 内外判断 O(1);采样需迭代求解器 | 求值 O(1);局限性大(非函数曲线无法表示) | 求值 O(1);采样 O(n);求导 O(1) |
| 图形学应用 | 碰撞检测、CSG建模、距离场渲染、SDF字体 | 高度场、地形截面、简单图表 | 动画路径、曲线造型、字体轮廓、CAD/CAM、相机路径 |
注意,显式表示 y=f(x) 实际上是参数表示的特殊退化形式(令 t=x, f(t)=(t, f(t))),同时也是隐式表示 y−f(x)=0 的特例。由于显式表示的局限性太大(无法表示闭合曲线、多值曲线和垂直切线),它在严肃的曲线理论中很少作为独立的讨论对象。以下我们重点对比隐式与参数式两种核心表示。
为什么参数表示在图形学中占主导地位
在计算机图形学的几乎所有子领域——实时渲染、动画、几何建模、字体渲染——参数表示都是默认的曲线表示方式。这一选择并非偶然,而是由以下四个深层次原因决定的:
理由一:易于采样。渲染管线的核心任务是将几何描述转化为屏幕像素。参数表示的优势在这里最为突出:只需在参数区间上均匀递增 t,就可以得到一系列按顺序排列的曲线点,直接送入光栅化器。隐式表示要做同样的事情,需要求解方程 f(x,y)=0 在网格上的根——这是数值计算中成本高且容易出错的操作。对于实时渲染每秒 60 帧的需求,参数表示的采样效率是不可替代的。
理由二:切线与法线计算简单。在着色、纹理映射和几何处理中,曲线的切向量和法向量是必需的——例如真实感渲染需要法线信息来计算光照。参数表示的切向量只需对分量分别求导:f'(t) = (x'(t), y'(t)),而隐式表示需要计算梯度 ∇f = (∂f/∂x, ∂f/∂y) 作为法线方向,再旋转 90 度得切线。对于高次或复杂函数,偏导数的计算和规范化会变得繁琐。参数形式的求导是分量独立的——x'(t) 和 y'(t) 分别计算——这极大地简化了 GPU 上的并行求值。
理由三:适合分段表示。复杂曲线几乎总是通过拼接多段简单的曲线片段来构造——这要求每一段都能够独立地参数化到单位区间 [0,1] 上。参数表示天然支持这种分段策略:每段一个参数函数 fᵢ(u), u∈[0,1],通过拼接条件连接。隐式表示的分段则需要分片定义函数的区域,并在区域边界上保证隐式方程的连续性——这比参数连续性的处理要复杂得多。
理由四:天然适合动画与运动控制。动画的本质是参数曲线的连续播放——参数 t 充当时间轴,f(t) 给出物体在每个时刻的位置。改变速度就是改变重参数化函数。这种"参数即时间"的直觉使得关键帧插值、相机路径规划、缓动曲线设计等任务都可以在统一的参数曲线框架内完成。隐式表示在动画中几乎没有用武之地,因为从"现在的位置"到"下一个位置"并没有自然的序列关系。
请记住,曲线是一个点集。这些表示为我们提供了指定这些集合的方法。任意一条曲线都有许多种可能的表示。正因如此,数学家通常会很小心地区分曲线本身和它的表示。在计算机图形学中,我们往往不够严谨——因为我们通常只提到表示,而不是实际的曲线本身。所以当有人说"一条隐式曲线"时,他们要么是指由某个隐式函数表示的曲线,要么是指作为某曲线的一个表示的隐式函数。这种区分通常并不重要,除非我们需要考虑同一条曲线的不同表示。我们在本章中将考虑不同的曲线表示,所以会更加小心。当我们使用"多项式曲线"这样的术语时,我们指的是可以由该多项式表示的曲线。
生活类比:曲线与其表示的关系,就像同一首歌的不同录音版本——一首歌是抽象的音乐作品(曲线),而MP3文件、CD音轨、现场录音都是它的不同表示(隐式/参数/生成式表示)。每一种"表示"都可以让你听到这首歌,但获取方式和使用便利性各不相同。
想一想:为什么参数表示是图形学中最常用的?如果你需要在屏幕上每秒绘制60次一条曲线,用隐式表示 x²+y²−r²=0 和用参数表示 (cos t, sin t) 各需要什么步骤?哪种更容易高效实现?
根据本章开头给出的定义,要成为一条曲线,它必须具有参数表示。然而,许多曲线也有其他表示。例如,二维中以原点为圆心、半径为1的圆可以写成隐式形式:
f(x, y) = x² + y² − 1 = 0
或以参数形式写成:
(x, y) = f(t) = (cos t, sin t), t ∈ [0, 2π)
参数形式不一定是给定曲线最方便的表示。事实上,可能存在一些具有简单隐式或生成式表示的曲线,却很难找到它们的参数表示。
曲线的不同表示各有优缺点。例如,参数曲线容易绘制得多,因为我们可以对自由参数进行采样。一般来说,参数形式是计算机图形学中最常用的,因为它们更容易操作。我们的重点将放在曲线的参数表示上。
一条参数曲线(parametric curve)指的是由某个特定的参数函数在某个特定区间上给出的曲线。更精确地说,一条参数曲线具有一个给定的函数,该函数是从参数区间的一个映射。把参数放在从0到1的单位区间上通常是方便的。当自由参数在单位区间上变化时,我们通常将参数记为 u。
如果我们把参数曲线视为用笔画出的线条,我们可以将 u = 0 视作笔第一次落在纸上的时刻,而将时间单位视为画完整条曲线所需的时间(u = 1 是曲线的终点)。曲线可以由一个将时间(以这些单位坐标计)映射到位置的函数来指定。本质上,曲线的指定就是一个能够回答"笔在时刻 u 的位置在哪里?"这一问题的函数。
如果给我们一个函数 f(t),它在区间 [a, b] 上指定了一条曲线,我们可以很容易地定义一个新函数 f₂(u),在单位区间上指定同一条曲线。我们可以首先定义:
g(u) = a + (b − a) u
然后:
f₂(u) = f(g(u))
两个函数 f 和 f₂ 都表示同一条曲线;然而,它们提供了曲线的不同参数化。为已有曲线创建新参数化的过程称为重参数化(reparameterization),而从旧参数到新参数的映射(本例中的 g)称为重参数化函数(reparameterization function)。
生活类比:把重参数化想象成同一段旅程的不同开车方式。你可以全程匀速行驶(均匀参数化),也可以起步缓慢、然后加速(非均匀参数化)。两种方式走的是同一条路(同一几何曲线),但你在每个"时间点"所处的位置完全不同。弧长参数化就像是"按照里程碑来开车"——每经过一公里,里程碑就推进一格,无论你的车速如何。
如果我们已经通过某种参数化定义了一条曲线,则存在无穷多种其他参数化(因为我们总是可以重参数化)。能够拥有曲线的多种参数化是有用的,因为它允许我们创建方便的参数化。然而,这也可能带来问题,因为它使得比较两个函数以判断它们是否表示同一条曲线变得困难。
这个问题的本质更为一般:自由参数(或时间元素)的存在为我们的曲线表示添加了一个不可见的、可能未知的元素。当我们在曲线画完之后观察它时,我们不一定知道时间信息。笔可能在整个时间区间内以恒定速度移动,也可能开始缓慢、后来加速。例如,虽然 u = 0.5 是参数空间的一半,但如果笔的运动开始时慢、结束时快,它可能并非曲线路径上的一半。考虑以下非常简单曲线的几种表示:
(x, y) = f(u) = (u, u) (x, y) = f(u) = (u², u²) (x, y) = f(u) = (u⁵, u⁵)
三个函数在单位区间上都表示同一条曲线;然而当 u 不是0或1时,f(u) 指向不同的点,取决于曲线的表示。
想一想:如果给你两条参数曲线 f(t)=(t, t²) 和 g(u)=(u³, u⁶),你能判断它们是否表示同一条几何曲线吗?需要什么数学条件?(提示:检查是否存在严格单调的重参数化函数将两者联系起来。)
如果给定一条曲线的参数化,我们可以直接将其用作曲线的指定,也可以开发一个更方便的参数化。通常,自然参数化(natural parameterization)是以一种对指定曲线来说方便(或自然)的方式创建的,所以我们不必了解速度沿曲线如何变化。
如果我们知道笔以恒定速度移动,那么自由参数的值就会更有意义。参数空间的中点就是曲线上的中点。参数可以不被理解为时间,而被理解为沿曲线的长度度量。这样的参数化称为弧长参数化(arc-length parameterization),因为它们通过函数来定义曲线,该函数将沿曲线的距离(即弧长)映射为位置。我们通常用变量 s 来表示弧长参数。
从技术上讲,如果一条参数化其切向量(即参数化关于参数的导数)的大小具有恒定长度,则该参数化就是弧长参数化。表达为方程:
|df(s) / ds| = c²
沿曲线计算长度可能比较棘手。一般来说,它由导数大小的积分来定义(直观地说,导数的大小就是笔沿曲线移动时的速率)。所以,给定参数值 v,你可以计算 s(沿曲线从点 f(0) 到点 f(v) 的弧长距离)为:
s = ∫₀ᵇ |df(t)/dt| dt (15.1)
其中 f(t) 是以自然参数化定义曲线的函数。
要使用弧长参数化,需要能够从方程 (15.1) 中给定 s 解出 t。对于我们研究的许多曲线类型,这无法以封闭形式(简单形式)完成,而必须通过数值方法求解。
一般来说,我们用变量 u 表示在单位区间上取值的自由参数,用 s 表示弧长自由参数,用 t 表示不属于前两者之一的参数。
想一想:为什么对于绝大多数曲线,弧长参数化的反函数没有解析表达式?以抛物线 f(t)=(t, t²) 为例,弧长积分 s=∫√(1+4t²)dt 虽然可以数值计算,但反函数 t(s) 无法写成初等函数。这意味着什么?在图形学实践中我们如何应对这一困境?
弧长参数化为什么是"黄金标准"
弧长参数化——记为 s-参数化——具有三个令所有其他参数化望尘莫及的理想性质:
性质一:恒速遍历。当参数以恒定速率 Δs 递增时,曲线上的采样点以恒定的空间间距分布。这意味着在屏幕上绘制时,采样点既不会在平直区域浪费像素,也不会在弯曲区域留下缝隙。更一般地,|f'(s)| ≡ 1 保证了参数 s 的每一步对应曲线上等长的位移——这正是"弧长"一词的由来。对于动画而言,这意味着物体以恒定的物理速度沿曲线运动,不会出现"时快时慢"的运动伪影。
性质二:曲率公式极简。在弧长参数化下,曲率退化为一个极其简洁的公式:κ(s) = |f''(s)|。也就是说,f''(s) 的大小直接就是曲线的弯曲程度——f''(s) 的方向指向曲率中心,大小等于曲率半径的倒数。而在任意参数化下,曲率的计算公式复杂得多:κ = |f'×f''| / |f'|³。分母的 |f'|³ 正是为了"消除"非弧长参数化引入的速度变化——弧长参数化直接把这个因子归一化掉了。
性质三:理论上的优雅。微分几何中几乎所有曲线理论的标准形式都以弧长参数化表述:Frenet-Serret 公式(T'=κN, N'=-κT+τB, B'=-τN)默认 s 为参数;曲率定义为 |T'(s)|;挠率定义为 -B'(s)·N(s)。这种优雅性使得弧长参数化成为理论研究的标准工具。
为什么在实践中很少使用?尽管弧长参数化具有上述理论优势,它在实际系统中却鲜少直接使用。核心原因是:对绝大多数曲线(除直线、圆、螺旋线等极少数特例外),从自然参数 u 到弧长 s 的映射 s(u) = ∫₀ᵘ |f'(t)| dt 没有封闭形式的反函数 u(s)。这意味着给定 s 值无法直接算出对应的 u 值——必须在运行时通过数值方法(如 Newton-Raphson 迭代或预计算查找表)来求解。在实际系统中,这一困境的应对策略有三种:(1) 预计算弧长表——对 u 均匀采样,计算累积弧长,建立 (s,u) 查找表,运行时二分查找加线性插值;(2) 使用自适应步长——在求值/渲染时根据局部速率动态调整参数步长,使空间步长趋于均匀;(3) 选择"近似弧长"的参数化——如弦长参数化或向心参数化,它们虽然不如弧长精确,但在实践中通常"足够好"。
总结起来:弧长参数化是理论的黄金标准,但在实践中更多作为"理想目标"——我们通过数值近似或巧妙的参数化选择来逼近它,而不是直接使用它。
对于某些曲线,定义一个表示其形状的参数函数是容易的。例如,直线、圆和椭圆都有简单的函数,可以用一个参数来定义它们包含的点。对于许多曲线来说,找到一个指定其形状的函数可能是困难的。我们用来创建复杂曲线的主要策略是分而治之(divide-and-conquer):我们将曲线分解为若干更简单的更小片段,每个片段具有简单的描述。
例如,考虑图15.1中的曲线。前两条曲线很容易用两段来指定。对于图15.1(b)中的曲线,我们需要两种不同类型的片段:一个线段和一个圆弧。
要为复合曲线(如图15.1(b)中的曲线)创建参数表示,我们需要让参数函数在表示各片段的函数之间切换。如果我们定义参数函数在区间 0 ≤ u ≤ 1 上,则图15.1(a)或(b)中的曲线可以定义为:
f₁(2u) 如果 u ≤ 0.5,
f(u) = {
f₂(2u − 1) 如果 u > 0.5, (15.2)
其中 f₁ 是第一段的参数化,f₂ 是第二段的参数化,并且这两个函数都定义在单位区间上。
我们需要小心定义函数 f₁ 和 f₂,以确保各曲线片段能够拼接在一起。如果 f₁(1) ≠ f₂(0),那么我们的曲线片段将不会连接,无法形成一条单一的连续曲线。
为了表示图15.1(b)中的曲线,我们需要使用两种不同类型的片段:一个线段和一个圆弧。为了简单,我们可能偏好使用单一类型的片段。如果我们试图仅用一种类型的片段(线段)来表示图15.1(b)中的曲线,我们将无法精确地重新创建该曲线(除非我们使用无穷多片段)。虽然由线段组成的新曲线(如图15.1(c))在形状上可能与图15.1(b)不完全相同,但对我们的使用来说可能足够接近了。在这种情况下,我们可能更愿意使用更简单的线段片段,而不是去获取一个更精确地表示该形状的曲线。
还要注意,随着我们使用越来越多的片段,我们可以得到更好的逼近。在极限情况下(使用无穷多片段),我们可以精确地表示该形状。
想一想:用线段逼近曲线时,多少段才算"够"?这取决于什么因素?考虑渲染分辨率、曲线曲率、以及人眼对平滑度的感知阈值。在图形学中,一个常用的经验法则是:当一段线段在屏幕空间上的投影长度小于1个像素时,继续细分就没有视觉意义了。
在计算机图形学出现之前,人们在绘图时就已经开始使用细木条或金属条(称为样条,splines)来绘制平滑曲线。这些物理样条被放置在纸上的若干指定点处,它们弯曲形成的形状就定义了一条通过所有这些点的平滑曲线。以物理样条命名的数学样条被设计用来模仿这种行为:它们是一组分段多项式函数,在数据点之间提供平滑的曲线。
使用许多低次多项式片段来表示曲线的一个重要优势在于,每个片段都是简单的,并且在不同片段类型之间切换的能力给了我们很大的灵活性。在图形学中,样条被用来表示所有类型的曲线——从字体轮廓到动画路径再到三维表面。数学样条与物理样条的关键区别在于,数学样条的分段性质使它们更容易在计算机中表示和操作。
生活类比:样条的思想就像用乐高积木搭出一条弯曲的轨道。每块积木本身只是一小段直轨(低次多项式),但当许多块拼接在一起时,整体轨迹可以非常顺滑地弯曲。关键在于每块积木之间的"接口"——如果接口设计得当,轨道整体就能平滑过渡,你看不出任何拼接痕迹。这就是样条的核心:用简单碎片拼接出复杂的平滑形状。
在学习了如何用参数形式表示曲线之后,我们现在来考虑曲线的一些基本性质。对于由多个曲线片段拼接而成的曲线,最关键的性质是片段在接合处的平滑程度。这种平滑程度由连续性(continuity)的概念来精确刻画。
由于我们要使用多段曲线片段来创建单一的长曲线,曲线片段在接合处的行为至关重要。连续性(continuity)是对曲线在拼接点处平滑程度的度量。我们可以定义几种不同级别的连续性:
参数连续性 Cn:参数连续性要求直到 n 阶的导数在拼接点处完全相等。具体来说:
f₁(1) = f₂(0)。这意味着曲线没有断开,但可能有一个可见的角点。f₁'(1) = f₂'(0)。这意味着切线(速度向量)在拼接点处的大小和方向都相同。曲线不会出现尖锐的角点,过渡是平滑的。f₁''(1) = f₂''(0)。这意味着曲率(弯曲程度的变化率)也是连续的。对于汽车外壳等高反射表面,C² 是行业标准。更一般地,如果一条曲线的所有导数(直到 n 阶)在拼接点处都连续,则称其具有 Cn 连续性。
想一想:如果一条曲线在所有地方都具有 C∞ 连续性(无限阶可导),它有什么特点?这种曲线的一个例子是什么?单段多项式曲线就具有 C∞ 连续性——那么为什么我们还需要拼接曲线呢?(提示:考虑高次多项式的振荡问题和局部控制需求。)
几何连续性 Gn:参数连续性对曲线的参数化方式施加了严格的约束。在很多情况下,我们只关心曲线的几何形状,而不关心参数化的具体速度。几何连续性放宽了参数连续性的要求,仅要求几何形状平滑过渡。
k > 0 使得 f₁'(1) = k · f₂'(0)。这意味着两段曲线在拼接点处共享同一条切线,但参数速率可以不同。κ₁(1) = κ₂(0)。这意味着弯曲程度平滑过渡,不会出现曲率的突然跳变。生活类比:C¹ 和 G¹ 的区别就像是两辆在交叉路口相遇的汽车。C¹ 要求两辆车不仅方向相同,而且速度也相同——它们"同步"驶入交叉口。G¹ 只要求方向相同——一辆可以比另一辆更快,但只要它们朝同一个方向行驶,几何路径就是平滑的。在汽车设计中,G² 就像是要求不仅方向平滑、而且方向盘的转动速率也不突变——乘客感受不到"顿挫"。
在实践中,几何连续性比参数连续性更为灵活,因为它允许设计者在保持几何平滑度的同时自由调整参数化。对于大多数视觉应用(如渲染、动画),G¹ 和 G² 已经足够,因为人眼无法区分参数速率的差异。
以下表格总结了各连续级别的条件与视觉表现:
| 连续级别 | 数学条件 | 视觉表现 | 典型应用 |
|---|---|---|---|
| C⁰ / G⁰ | f₁(1) = f₂(0) | 不断开,可能有角点 | 多边形线 |
| G¹ | f₁'(1) = k · f₂'(0), k > 0 | 切线方向连续,无角点 | 矢量字体轮廓 |
| C¹ | f₁'(1) = f₂'(0) | 切线大小和方向都连续 | 动画路径 |
| G² | κ₁(1) = κ₂(0) | 曲率值连续,丝滑过渡 | 汽车外壳设计 |
| C² | f₁''(1) = f₂''(0) | 二阶导数向量相等 | 高精度CAD |
想一想:为什么在工业设计中 G² 比 C² 更常用?斑马条纹反射测试中,G² 和 C² 的表面有肉眼可见的区别吗?实际上没有——人眼只能感知曲率 κ 的突变,而无法分辨二阶导数向量的长度差异。G² 保留了更多的设计自由度,同时提供了相同的视觉品质。
在讨论曲线的拼接和连续性时,我们反复提到"切线""曲率"和"二阶导数"。这些概念背后是一个强大而优雅的数学框架——Frenet-Serret 坐标系(Frenet-Serret frame),它将曲线在每一点处的局部几何行为完全刻画为三个相互正交的单位向量及其变化率。
Frenet-Serret 公式的几何直觉
考虑一条弧长参数化的空间曲线 f(s)。在每一点 s 处,我们可以定义三个两两正交的单位向量,它们构成了一个"移动的局部坐标系"——就像沿着曲线滑行的三脚架:
切向量(Tangent): T(s) = f'(s) —— 曲线前进的方向 主法向量(Normal): N(s) = T'(s) / |T'(s)| —— 曲线弯曲的方向 副法向量(Binormal): B(s) = T(s) × N(s) —— 垂直于弯曲平面的方向
这三个向量按 T → N → B 的顺序构成右手系。关键的是,它们的导数相互关联,这就是著名的 Frenet-Serret 公式:
T'(s) = κ(s) · N(s) —— 切线沿法线方向弯曲 N'(s) = −κ(s) · T(s) + τ(s) · B(s) —— 法线同时被曲率和挠率拉动 B'(s) = −τ(s) · N(s) —— 副法线沿法线方向扭转
其中 κ(s) 是曲率(curvature),τ(s) 是挠率(torsion)。
这些公式的几何解释极其直观:
生活类比:Imagine you're driving a car along a mountain road. The tangent T is the direction your headlights point. The normal N is the direction you're turning the steering wheel (left/right on a flat road, or up/down on a hill). The binormal B is the direction "straight up" out of the car's roof. If the road is flat (τ=0), B never changes—the car never rolls. If the road twists like a corkscrew (τ≠0), B rotates around T—the car rolls as it turns. The curvature κ tells you how hard you're turning the wheel; the torsion τ tells you how much the road is banking.
平面曲线的 Frenet-Serret 简化形式
对于平面曲线(所有点都在一个二维平面内),挠率 τ(s) ≡ 0(曲线从未"扭出"该平面)。Frenet-Serret 公式退化为极其简洁的二维形式:
T'(s) = κ(s) · N(s) —— 切线转向法线 N'(s) = −κ(s) · T(s) —— 法线转向切线的反方向
在平面中,N 可以简单地从 T 逆时针旋转 90 度得到:若 T = (tₓ, t_y),则 N = (−t_y, tₓ)。此时 Frenet-Serret 公式完全由曲率 κ(s) 这一个标量函数决定——积分 κ(s) 即可唯一恢复曲线的几何形状(在刚体运动等价意义下)。这就是"平面曲线基本定理":一条平面曲线由其曲率函数 κ(s) 唯一确定(加上初始位置和方向)。
这个结论具有深远的实际意义:如果你在设计一条平面曲线,你所做的事情本质上就是在"画出一个曲率函数 κ(s)"。Bézier 曲线的凸包性质、B 样条的变差缩减性质——归根结底都是对 κ(s) 的间接约束。
曲率的物理类比——驾车转弯
曲率的最直观物理类比来自日常驾驶经验:
方向盘转动的角度(除以车速)直接正比于道路的曲率——这是曲率的最朴实定义。法向加速度 aₙ = κ · v²(v 是车速),这也解释了为什么急弯需要减速:即使 κ 固定,v 翻倍则侧向力翻四倍。
在数学上,曲率的严格定义给出了这一物理直觉的精确版本:
κ = |f' × f''| / |f'|³
这个公式的精妙之处在于分母 |f'|³——它消除了参数化速度的影响,使 κ 成为纯粹的几何量。无论你是匀速行驶还是忽快忽慢,同一条道路的曲率函数是相同的。对于弧长参数化(|f'(s)| ≡ 1),公式简化为 κ = |f''(s)|——二阶导数的大小直接就是曲率。这就是为什么在理论研究中使用弧长参数化最为优雅。
曲率还有一个极其优雅的几何解释:κ = 1/R,其中 R 是曲线在该点处的密切圆(osculating circle)的半径。密切圆是在该点与曲线"最佳吻合"的圆——它与曲线共享位置、切线方向和曲率。曲率越大意味着密切圆越小,曲线弯曲得越"紧";曲率越小意味着密切圆越大,曲线越接近于直线(极限情况下,直线的 κ=0 对应于半径为无穷大的圆)。设计曲线时,检查沿曲线的密切圆半径分布(曲率梳图,curvature comb)是工业设计中的标准诊断手段——任何曲率的不连续跳变在曲率梳图中都清晰可见。
现在我们转向表示曲线片段的实际方法。最自然的选择是多项式,因为它们简单、可无限次求导、且在计算机中易于求值。我们将看到,低次多项式(尤其是一、二、三次)是图形学中最常用的曲线构建模块。
一个 n 次多项式的一般形式为:
f(t) = a₀ + a₁t + a₂t² + ... + aₙtⁿ (15.3)
其中 a₀, ..., aₙ 是系数。n+1 个系数给出了 n+1 个自由度。在二维中,每个系数是一个二维向量(即 aᵢ = (aᵢₛ, aᵢₜ)),因此一个 n 次二维多项式曲线共有 2(n+1) 个标量自由度。
我们可以将多项式写成点积形式,将变量分离到一侧:
f(t) = [1 t t² ... tⁿ] · [a₀ a₁ a₂ ... aₙ]ᵀ
这种形式方便用矩阵运算来处理多项式曲线。
一次(线性)多项式从点 p₀ 到 p₁ 的直线段是最简单的多项式曲线:
f(u) = (1 − u) p₀ + u p₁ (15.4)
这种形式称为重心坐标(barycentric coordinates)表示,因为系数 (1−u) 和 u 的和总是1。这意味着曲线上的每个点都是端点的仿射组合(affine combination)。当 u ∈ [0, 1] 时,系数非负,每个点是端点的凸组合(convex combination),因此线段完全落在端点的凸包(convex hull)内。
将 (15.4) 展开为多项式形式:
f(u) = p₀ + (p₁ − p₀) u
显式给出了 "位置" + "方向 × 参数" 的形式。导数 f'(u) = p₁ − p₀ 是常向量(切线方向),二阶导数为零——这是直线段的几何本质。
虽然直线段非常有用,但我们通常需要更灵活的形状。为此,我们使用更高次的多项式。二次多项式(n = 2)提供三个控制系数的自由度:
f(u) = a₀ + a₁u + a₂u² (15.5)
��二维中,六个标量自由度(三个二维向量)足以指定一条抛物线弧。然而,二次曲线只能是抛物线——它们无法产生拐点(inflection point),因为二阶导数是常数向量,弯曲方向始终不变。
二次 Bézier 曲线的局限性——一个严格证明
为什么二次曲线(尤其是二次 Bézier)不能产生拐点?这可以从其二阶导数的结构来严格证明。一条二次 Bézier 曲线由三个控制点 b₀, b₁, b₂ 定义:
f(t) = (1−t)²·b₀ + 2t(1−t)·b₁ + t²·b₂, t ∈ [0, 1]
对其求一阶导数和二阶导数:
f'(t) = 2[(1−t)(b₁−b₀) + t(b₂−b₁)] f''(t) = 2(b₂ − 2b₁ + b₀) = 常数向量
二阶导数 f''(t) 是一个常数向量——它不随 t 变化。这意味着整条曲线的"加速度"方向是固定的。在平面曲线中,拐点发生在曲率 κ 变号的时刻——即 f' × f'' 的符号发生翻转。对于二次 Bézier:
f'(t) × f''(t) = 2(b₀b₁b₂ 的有向面积相关的线性函数) × 常数向量
由于 f'' 是常数,叉乘 f' × f'' 是 t 的线性函数——它最多有一个根。这意味着二次 Bézier 曲线的曲率符号最多变化一次,而且必须在 f' ∥ f'' 的时刻。但若三个控制点不共线,这个方程在 [0,1] 内最多有一个解(且通常不在区间内)。
更直观地看:三个控制点最多定义了一个"弯"——曲线从 b₀ 出发,被 b₁ "拉"向一侧,然后在 b₂ 结束。这整个过程只涉及一个方向上的弯曲。要产生 S 形曲线(先向左弯再向右弯,或反之),曲线需要至少四个控制点——这就是为什么三次 Bézier(4 个控制点)成为图形学中最常用的次数。三次曲线的二阶导数是 t 的线性函数:f''(t) 可以从正值变为负值(或反之),从而产生真正的拐点。
总结:二次 Bézier = 无拐点 + 无局部控制(只有 3 个控制点,改了任何一个则全曲线变形)+ 只能表示抛物线。三次 Bézier = 可以有拐点 + 虽然也无局部控制但形状更丰富 + 可以近似各种样条。这个简单的事实解释了为什么所有主流的矢量图形系统(SVG、PostScript、TrueType outlines)都以三次曲线为核心。
三次多项式(cubic,n = 3)是图形学中最常用的次数:
f(u) = a₀ + a₁u + a₂u² + a₃u³ (15.6)
三次曲线具有恰好的自由度:足够低以避免高次多项式的振荡问题(Runge 现象),又足够高以提供显著的灵活性(拐点、S 形曲线)。在二维空间中,8个标量自由度(四个二维向量)允许我们指定两个端点的位置(4个约束)和两个端点的切线(4个约束)。这就是三次多项式成为图形学"黄金次数"的根本原因。
想一想:为什么三次而不是四次或五次?高次多项式的主要问题是振荡——如果你拖动一个控制点,整条曲线都会剧烈波动(这被称为 Runge 现象)。此外,高次多项式缺乏局部控制——修改任意控制点都会影响整条曲线。三次多项式恰好达到了"灵活性"和"稳定性"之间的最佳平衡。
我们在 (15.6) 中给出的形式使用了系数基(或称为单项式基){1, t, t², t³}。虽然系数基求导方便,但它与曲线形状之间没有直观的对应关系。设计师更希望用几何量来控制曲线——如端点的位置和切线——而不是抽象的系数。
我们可以通过指定约束条件来从几何量计算出系数。对于三次曲线,我们通常指定四个几何约束(如两个端点的位置和两个端点的切线),然后解出四个系数。这个过程可以用矩阵形式表达。
将三次多项式写成矩阵形式:
f(u) = [1 u u² u³] · [a₀ a₁ a₂ a₃]ᵀ = u · a (15.7)
其中 u 是参数值的行向量(称为幂基向量),a 是系数列向量。
现在,如果我们有一组几何约束(例如端点位置和切线),它们可以表示为系数向量的线性变换。例如,如果我们想指定 f(0)、f(1)、f'(0) 和 f'(1)(即 Hermite 条件),我们可以写出:
f(0) = a₀ f(1) = a₀ + a₁ + a₂ + a₃ f'(0) = a₁ f'(1) = a₁ + 2a₂ + 3a₃
写成矩阵形式 p = C · a,其中 p 是几何约束向量,C 是约束矩阵(constraint matrix):
[f(0) ] [1 0 0 0] [a₀] [f(1) ] = [1 1 1 1] · [a₁] [f'(0)] [0 1 0 0] [a₂] [f'(1)] [0 1 2 3] [a₃]
对该矩阵求逆,我们可以从几何约束解出系数:
a = C⁻¹ · p
于是曲线可以表示为:
f(u) = u · C⁻¹ · p = b(u) · p (15.8)
其中 b(u) = u · C⁻¹ 称为混合函数(blending functions)。矩阵 B = C⁻¹ 称为基矩阵(basis matrix)——它的行给出了每个几何约束在构造曲线时的权重函数。
对于 Hermite 约束,约束矩阵的逆为:
C⁻¹ = [ 1 0 0 0 ]
[ 0 0 1 0 ]
[-3 3 -2 -1 ]
[ 2 -2 1 1 ]
因此 Hermite 混合函数(即三次 Hermite 基函数)为:
b(u) = [1 u u² u³] · C⁻¹
= [1−3u²+2u³, 3u²−2u³, u−2u²+u³, −u²+u³]
= [H₀³(u), H₃³(u), H₁³(u), H₂³(u) ]
其中 Hᵢ³(u) 是三次 Hermite 基函数。这样,Hermite 曲线可以写成:
f(u) = H₀³(u)·f(0) + H₃³(u)·f(1) + H₁³(u)·f'(0) + H₂³(u)·f'(1)
将上述 Hermite 基函数展开验证其插值条件:
H₀³(u) = 1 − 3u² + 2u³ → H₀³(0)=1, H₀³(1)=0, H₀³'(0)=0, H₀³'(1)=0 H₃³(u) = 3u² − 2u³ → H₃³(0)=0, H₃³(1)=1, H₃³'(0)=0, H₃³'(1)=0 H₁³(u) = u − 2u² + u³ → H₁³(0)=0, H₁³(1)=0, H₁³'(0)=1, H₁³'(1)=0 H₂³(u) = −u² + u³ → H₂³(0)=0, H₂³(1)=0, H₂³'(0)=0, H₂³'(1)=1
每个基函数恰好"激活"它负责的唯一约束条件——这是一种精妙的插值设计。
想一想:为什么基矩阵可以让我们在"系数表示"和"几何表示"之间自由切换?关键是什么数学性质保证了这种转换是可逆的?(提示:约束矩阵 C 是否总是满秩的?什么情况下约束矩阵可能不可逆?)
为了帮助读者彻底理解基矩阵方法,以下以三次 Hermite 曲线为例,给出从原始定义到最终混合函数的完整六步推导过程。这一推导是理解所有曲线基矩阵理论的基础模板。
第一步:设定通用三次多项式形式。我们要构造一条定义在 u∈[0,1] 上的三次曲线:
f(u) = a₀ + a₁u + a₂u² + a₃u³ f'(u) = a₁ + 2a₂u + 3a₃u²
其中 a₀, a₁, a₂, a₃ 是四个待定的向量系数(在二维中每个是二维向量,共 8 个标量自由度)。
第二步:列出端点插值条件。Hermite 形式要求曲线满足四个条件——起点位置 f(0)、终点位置 f(1)、起点切线 f'(0)、终点切线 f'(1):
f(0) = p₀ (通过点 p₀) f(1) = p₁ (通过点 p₁) f'(0) = m₀ (起点切线向量 = m₀) f'(1) = m₁ (终点切线向量 = m₁)
第三步:将端点条件代入多项式,建立方程组。将 u=0 和 u=1 分别代入 f(u) 和 f'(u):
u = 0: f(0) = a₀ = p₀
f'(0) = a₁ = m₀
u = 1: f(1) = a₀ + a₁ + a₂ + a₃ = p₁
f'(1) = a₁ + 2a₂ + 3a₃ = m₁
第四步:写出向量-矩阵形式的约束方程。将上述四个方程组装成矩阵形式 p = C·a:
[p₀] [1 0 0 0] [a₀] [p₁] = [1 1 1 1] · [a₁] [m₀] [0 1 0 0] [a₂] [m₁] [0 1 2 3] [a₃]
约束矩阵 C 的每一行对应一个几何约束条件。例如,第一行 [1,0,0,0] 使得 a₀ = p₀,第四行 [0,1,2,3] 使得 a₁+2a₂+3a₃ = m₁。注意 C 的行列式为 det(C) = 1——因为该矩阵是上三角矩阵,且主对角线元素全为 1(1×1×1×3=3... 实际上 C 不是上三角的——让我们验证:det(C) = 1×(1×0×3 − 1×2×0 − 1×0×0 + ...)。实际上 C 的行列式通过计算可知为 1(或一个非零值),这意味着 C 可逆,因此可以唯一解出系数 a。
第五步:求约束矩阵的逆 C⁻¹,解出系数。通过矩阵求逆运算(或直接求解上述四个方程的代数解):
a₀ = p₀ a₁ = m₀ a₂ = −3p₀ + 3p₁ − 2m₀ − m₁ a₃ = 2p₀ − 2p₁ + m₀ + m₁
写成矩阵形式即得 C⁻¹(前面已给出)。验证:将 a₀,...,a₃ 代入 f(1) = a₀+a₁+a₂+a₃ = p₀+m₀+(−3p₀+3p₁−2m₀−m₁)+(2p₀−2p₁+m₀+m₁) = p₁ ✓。类似可验证其他三个条件。
第六步:构造混合函数 b(u) = u·C⁻¹,得到最终表达式。
b(u) = [1 u u² u³] · C⁻¹
= [(1−3u²+2u³), (3u²−2u³), (u−2u²+u³), (−u²+u³)]
= [H₀³(u), H₃³(u), H₁³(u), H₂³(u)]
因此,对于任意 u∈[0,1],曲线上的点可以直接通过加权和计算:
f(u) = H₀³(u)·p₀ + H₃³(u)·p₁ + H₁³(u)·m₀ + H₂³(u)·m₁
这六个步骤——设定多项式形式→列出几何约束→代入求方程→组装矩阵→求逆矩阵→构造混合函数→——构成了所有多项式曲线片系统的基础推导模板。Bézier、Catmull-Rom 等曲线只是用了不同的几何约束 p 和对应的约束矩阵 C,其余步骤完全相同。
验证 Hermite 基函数的几何意义:
值得注意的是,H₁³ 和 H₂³ 在 u=0 和 u=1 处的函数值都为 0,但它们的导数在端点处非零——这意味着切线向量的改变不会移动曲线的端点位置,只改变曲线"离开"端点的角度。这一性质对于交互设计至关重要:用户可以独立调整端点处切线的长度来改变曲线的"张力",而不必担心端点位置漂移。
混合函数(blending functions)是曲线表示的核心概念。它们是参数的函数,定义了每个几何约束(控制点、切线等)如何影响曲线上的每个点。方程 (15.8) 表明,对于任意参数值 u,曲线上的点 f(u) 是所有几何约束的加权和,其中权重就是混合函数在 u 处的值。
混合函数具有以下重要性质:
u 处的值之和恒为 1。这保证了曲线的仿射不变性——如果你对控制点施加一个仿射变换,曲线会随之变换。u = 0 和 u = 1 处分别满足特定的插值条件。混合函数的概念统一了所有多项式曲线表示:不同的曲线类型(Hermite、Bézier、Catmull-Rom、B 样条)的区别仅仅在于它们使用不同的基矩阵,从而产生不同的混合函数。
有时候,我们希望一条多项式曲线精确通过一组给定的数据点。这就是多项式插值问题。对于 n+1 个数据点,存在唯一的不超过 n 次的多项式通过这些点。
给定 n+1 个数据点 (tᵢ, pᵢ)(i = 0, ..., n),有唯一的多项式 f(t) 使得 f(tᵢ) = pᵢ 对所有的 i 成立。这个多项式可以用Lagrange 插值形式表示:
f(t) = Σᵢ₀ⁿ pᵢ · Lᵢⁿ(t)
其中 Lagrange 基函数 Lᵢⁿ(t) 定义为:
Lᵢⁿ(t) = Πᵣ≠ᵢ (t − tᵣ) / (tᵢ − tᵣ)
每个 Lᵢⁿ(t) 在 t = tᵢ 处的值为 1,在所有其他数据点的参数位置处的值为 0——这精确满足了插值条件。
然而,高次多项式插值存在严重的数值问题。虽然数学上对于 n+1 个点存在唯一的不超过 n 次的多项式,但当 n 增大时,多项式会在数据点之间剧烈振荡(经典的 Runge 现象)。此外,高次插值对数据点的微小扰动极为敏感——数据中极小的噪声会导致曲线形状的巨大变化。这就是为什么图形学中几乎总是使用分段低次多项式而不是单一高次多项式的原因。
想一想:如果你有100个数据点想要用一条光滑曲线连接,为什么不应该使用一个99次的多项式?考虑两方面的原因:(1) 数值不稳定性——99次多项式的系数可能极大或极小导致浮点溢出;(2) 形状失控——即便数据点排列整齐,高次多项式也会在点之间剧烈振荡。
生活类比:单一高次多项式插值就像用一根极长的弹性钢尺去穿过100个固定桩钉——钢尺会在桩钉之间剧烈弯曲振荡,远远偏离你直觉期望的"平滑路径"。分段低次插值则像是在每两个桩钉之间使用一段独立的短钢尺——每段都只受局部桩钉控制,整体平滑且可靠。这就是样条的核心设计哲学。
此前讨论的所有多项式曲线片有一个共同的根本局限:它们只能表示多项式曲线。圆、椭圆和其他圆锥曲线无法被多项式精确表示——只能被逼近。为了解决这一问题,我们将标准的(多项式)Bézier 曲线推广为有理 Bézier 曲线(rational Bézier curve),通过引入权重来突破多项式的限制。
从多项式到有理——核心思想
标准 n 次 Bézier 曲线定义为控制点 bᵢ 关于 Bernstein 基函数 Bᵢⁿ(t) 的加权和:f(t) = Σ Bᵢⁿ(t)·bᵢ。这本质上是对控制点的仿射组合(系数和为 1)。有理 Bézier 曲线在同一个结构上增加了一个额外的自由度——每个控制点获得一个标量权重 wᵢ:
f(t) = Σ wᵢ·Bᵢⁿ(t)·bᵢ / Σ wᵢ·Bᵢⁿ(t) (15.13b)
分母 Σ wᵢ·Bᵢⁿ(t) 是一个标量归一化因子。当所有权重相等(w₀ = w₁ = ... = wₙ = 1)时,分母恒为 1(因为 Σ Bᵢⁿ(t) = 1),有理 Bézier 退化为标准多项式 Bézier。当权重不相等时,每个控制点的影响比例不再是 Bᵢⁿ(t),而是 wᵢ·Bᵢⁿ(t) / Σ wⱼ·Bⱼⁿ(t)——这个比例在 t 的不同取值处可以微妙地改变。
齐次坐标视角——为什么"有理"可以精确表示圆
理解有理 Bézier 的最深刻方式是通过齐次坐标(homogeneous coordinates)。将每个二维控制点 bᵢ = (xᵢ, yᵢ) 提升到三维齐次空间:
b̂ᵢ = (wᵢ·xᵢ, wᵢ·yᵢ, wᵢ) ∈ ℝ³
其中第三分量就是该控制点的权重。然后在三维空间中构造一条标准多项式 Bézier 曲线:
F̂(t) = Σ Bᵢⁿ(t) · (wᵢ·xᵢ, wᵢ·yᵢ, wᵢ)
= ( Σ wᵢ·Bᵢⁿ(t)·xᵢ, Σ wᵢ·Bᵢⁿ(t)·yᵢ, Σ wᵢ·Bᵢⁿ(t) )
最后一步是将这个三维曲线投影回二维欧几里得平面——即对前两个分量除以第三个分量(齐次除法,perspective division):
f(t) = ( Σ wᵢ·Bᵢⁿ(t)·xᵢ / Σ wᵢ·Bᵢⁿ(t), Σ wᵢ·Bᵢⁿ(t)·yᵢ / Σ wᵢ·Bᵢⁿ(t) )
这正是有理 Bézier 的定义。关键洞察是:虽然在二维空间中这是一条有理曲线(分子和分母都是多项式),但在三维齐次空间中它是一条标准多项式曲线!这意味着所有适用于多项式 Bézier 的性质和算法(de Casteljau、凸包性质、细分等等)都可以在齐次空间中直接应用,唯一的额外步骤是在最后做一次齐次除法将结果投影回二维。
精确表示圆锥曲线——权重的魔力
二次有理 Bézier(n=2,三个控制点 b₀, b₁, b₂ 及其权重 w₀, w₁, w₂)可以精确表示所有圆锥曲线。核心是中间权重 w₁ 的取值:
w₁ = 1 → 抛物线(此时退化为标准二次 Bézier) w₁ < 1 → 椭圆弧 w₁ = cos(θ/2) → 圆弧(θ 为圆心角,w₀ = w₂ = 1) w₁ > 1 → 双曲线弧
以最常见的四分之一圆弧为例(单位圆从 (1,0) 到 (0,1)):
b₀ = (1, 0), w₀ = 1 b₁ = (1, 1), w₁ = cos(45°) = √2/2 ≈ 0.7071 b₂ = (0, 1), w₂ = 1
代入有理 Bézier 公式可以验证 f(t) = (x(t), y(t)) 满足 x² + y² = 1 对所有 t∈[0,1] 成立——这是一条精确的圆弧,而非近似!标准多项式 Bézier(w₁=1)给出的是抛物线逼近,距离真圆存在可测量的偏差。
权重 wᵢ 的几何意义——"引力强度"
权重 wᵢ 可以直观地理解为控制点 bᵢ 的"引力强度":
注意所有权重同时乘以同一个正常数不会改变曲线——因为分子和分母同时缩放,约掉了。只有权重的比值真正影响曲线的几何形状。习惯上设置 w₀ = wₙ = 1(首尾控制点权重为 1)作为参照。
有理 Bézier 是通往 NURBS 的关键一步。在 NURBS 中,Bernstein 基函数被替换为 B 样条基函数,其余的齐次坐标投影框架完全继承。理解了有理 Bézier 的齐次坐标解释,就为理解 NURBS 奠定了基础。
单段多项式曲线只能表达有限复杂度的形状。要创建任意复杂的曲线,我们需要将多个多项式片段拼接在一起。本节讨论拼接的机制与条件。
创建一条复杂曲线的最简单方法是指定它的每一段,然后将它们放在一起。在这种方法中,我们为曲线的每个片段定义一组独立的控制点(或几何约束)。这意味着我们有完全的自由来独立地调整每个曲线片段。
使用独立片段有两个主要缺点。首先,它倾向于产生大量的控制数据——每个片段都需要自己的一组控制点。其次,也是最关键的:如果片段是真正独立的,那么维持片段间平滑过渡的责任就完全落在了用户身上。如果用户不小心使相邻片段的切线不匹配,曲线就会出现可见的角点。在交互设计中,要保持多条独立片段之间的连续性是非常繁琐的。
更好的方法是使用共享控制点——让相邻的曲线片段共享一些控制数据,从而自动保证一定级别的连续性。这是现代曲线设计系统的核心思想。
例如,对于两段三次多项式曲线(分别定义在 u ∈ [0, 1] 的区间上),如果第二段的初始位置被强制等于第一段的终点位置(即共享端点),则 C⁰ 连续性自动得到满足。
为了达到 C¹ 连续性,第二段的初始切线必须被强制等于第一段的终点切线。这可以通过让两段共享切线向量来实现——但这需要用户显式指定切线。更好的方法是让切线自动由控制点位置导出,这正是 Bézier 曲线的做法。
对于 Bézier 曲线,端点切线方向由相邻控制点的连线决定。如果两段曲线共享连接点的控制多边形边,则 G¹ 连续性自然成立;如果共享边不仅方向相同而且长度也相同,则 C¹ 连续性成立。
一般地,要使 k 段拼接曲线达到 Cn 连续性,需要 n+1 个控制点被连续的曲线片段共享或受约束。这限制了系统的整体自由度,但换来了平滑度的保证。
想一想:在交互式曲线设计中,如果你拖动一个共享连接点,所有相连的曲线段都会随之更新。这是好事还是坏事?从"局部控制"的角度分析:一个控制点的修改应该影响多大的曲线范围?为什么在汽车设计中,局部控制比全局控制更重要?(提示:如果你想把车门把手上方的曲线微调一下,你希望整个车身都变形吗?)
由于 Bézier 曲线是图形学中最常用的拼接单元,我们在此给出其 C¹ 和 C² 拼接条件的完整代数推导。这些条件只需要控制点的共线/共面关系,不需要求解导数——这是 Bézier 形式的最大实用优势。
C¹ 拼接条件——三点共线且对称
设两段三次 Bézier 曲线 F(u)(控制点 a₀, a₁, a₂, a₃)和 G(u)(控制点 b₀, b₁, b₂, b₃)在连接点 J = a₃ = b₀ 处拼接。C¹ 连续性要求 F'(1) = G'(0)。利用 Bézier 的切线性质:
F'(1) = 3(a₃ − a₂) 第一段终点切线 G'(0) = 3(b₁ − b₀) 第二段起点切线
令两者相等:
3(a₃ − a₂) = 3(b₁ − b₀) ⇒ a₃ − a₂ = b₁ − b₀
由于 J = a₃ = b₀,代入得:
J − a₂ = b₁ − J ⇒ b₁ = 2J − a₂
这个条件的几何解释是:a₂, J, b₁ 三点共线,且 J 是 a₂ 和 b₁ 的中点。换句话说,连接点左右两侧相邻的控制点必须对称于连接点——这保证了切线向量的大小和方向都完全匹配。
C² 拼接条件——四点共面且线性相关
C² 连续性在 C¹ 的基础上进一步要求二阶导数不变:F''(1) = G''(0)。三次 Bézier 的二阶导数为:
F''(1) = 6(a₁ − 2a₂ + a₃) 第一段终点二阶导数 G''(0) = 6(b₀ − 2b₁ + b₂) 第二段起点二阶导数
令两者相等并约去因子 6:
a₁ − 2a₂ + a₃ = b₀ − 2b₁ + b₂
代入 C¹ 条件 b₁ = 2J−a₂(其中 J=a₃=b₀):
a₁ − 2a₂ + J = J − 2(2J−a₂) + b₂ ⇒ a₁ − 2a₂ = −4J + 2a₂ + b₂ ⇒ b₂ = a₁ − 4a₂ + 4J
这个条件将四个控制点 a₁, a₂, J, b₂ 联系在了一起。它与 C¹ 条件(a₂, J, b₁ 共线)一起构成了保证曲率连续所需的约束。请注意 C² 条件需要涉及连接点两侧各两个控制点(a₁, a₂ 和 b₁, b₂),而 C¹ 只需要各一个(a₂ 和 b₁)。这意味着一段曲线的 C² 连续性取决于其前后相邻曲线段的控制点——这解释了为什么构建一条 C² 连续的长曲线是全局问题(修改任何点都会传播到相邻几段)。
为什么 C² 需要超过 4 个控制点的链?
一条单独的三次曲线(4 个控制点)天然具有 C^∞ 连续性(因为是单个多项式)。但当我们要构造一条由多段三次 Bézier 拼接的 C² 连续曲线时,每新增一段只引入少量额外自由度(新控制点数 = 3 个新点减去 2 个连续性约束 = 净 1 个自由控制点)。实际上,要使 n 段曲线达到 C²,控制点序列中每连续 4 个控制点决定了中间一段曲线的二阶导数行为。这解释了为什么 C² 连续的长 Bézier 曲线几乎等价于 B 样条——后者通过节点向量的巧妙构造来原生地保证 C² 连续性。
虽然 C¹ 和 G¹ 都保证视觉上的切线连续(无角点),但两者的数学机制和应用场景有本质区别。下表从六个维度进行系统对比:
| 维度 | C¹(参数连续性) | G¹(几何连续性) |
|---|---|---|
| 数学条件 | F'(1) = G'(0) (切线向量完全相等) | F'(1) = k·G'(0), k > 0 (切线方向相同,长度成比例) |
| 物理直觉 | 两辆车以相同速度和方向驶过连接点 | 两辆车方向相同,但速度可能不同 |
| 对参数化速度的依赖 | 依赖——参数化速度必须连续 | 不依赖——只关心几何形状 |
| Bézier 条件 | a₂, J, b₁ 共线且 J 为中点 | a₂, J, b₁ 共线(比例自由) |
| 设计自由度 | 较低——额外约束锁定了切线长度 | 较高——切线长度可自由设计 |
| 典型应用 | 动画路径(需要恒定速度) | 字体轮廓、汽车设计、曲面拼接 |
G² 与 C² 的对比:
| 维度 | C²(参数连续性) | G²(几何连续性) |
|---|---|---|
| 数学条件 | F'(1)=G'(0) 且 F''(1)=G''(0) | 切线同向且 κ₁(1)=κ₂(0) (曲率值连续,参数速度自由) |
| 物理直觉 | 方向盘和油门都连续(速度+加速度连续) | 方向盘转动速率连续,但踩油门深浅可自由变化 |
| 视觉检测 | 斑马条纹无折痕,反射图无断裂 | 斑马条纹无折痕——与 C² 肉眼不可区分 |
| 设计灵活性 | 受参数化约束,设计空间较小 | 保留参数化自由度,设计空间更大 |
| 工业实践 | 主要在理论分析中使用 | 汽车/航空设计的事实标准 |
一个关键洞察:人眼无法区分 C² 和 G² 的表面质量。二者的视觉差异仅在于高光反射中参数速度引起的细微变化——这在实际光照条件下完全不可察觉。因此,G² 以更少的约束提供了相同的视觉品质,这是工业设计中 G² 被广泛采用的实用理由。在斑马条纹测试中(用条纹纹理映射到表面,观察反射条纹的连续性),G² 和 C² 的表现完全一致——条纹在拼接处不会出现断折。
理解 C/G 区分的最佳方式是将"参数连续性"视为对"参数函数的光滑性"的度量(与具体曲线的形状无关),而将"几何连续性"视为对"曲线作为几何对象的光滑性"的度量(与参数化无关)。所有的 G¹ 曲线也都是 C⁰(因为它们至少是连续的),但反过来不成立——C¹ 一定是 G¹,但 G¹ 不一定是 C¹。
三次多项式是图形学中最常用的曲线片段次数。本节详细讨论三次曲线的实际构造方法,特别是自然三次样条——一种经典的插值样条。
自然三次样条(natural cubic spline)是物理样条的数学模拟。给定一组 n+1 个数据点 p₀, ..., pₙ,自然三次样条由 n 段三次多项式组成——每段连接一对相邻数据点。该样条具有以下特性:
∫ (f''(u))² du。自然三次样条通过求解一个线性方程组来构造。设第 i 段曲线(在数据点 pᵢ 和 pᵢ₊₁ 之间)定义在参数区间 u ∈ [0, 1] 上(经过适当的参数变换)。我们需要对每段的三次多项式确定其四个系数(即每段4个未知数,共 4n 个未知数)。
约束条件来自:
pᵢ 和 pᵢ₊₁(2n 个条件)。n−1 个内部拼接点处的一阶导和二阶导必须相等(2(n−1) 个条件)。这给出了 4n − 2 个约束,但共有 4n 个未知数,因此还有 2 个自由度未定。这两个自由度由两个端点条件(end conditions)来确定。
常见的端点条件包括:
f''(0) = 0 和 f''(n) = 0。这模仿了物理样条在两端不受力矩作用时的行为,也是"自然"样条名称的由来。构造自然三次样条需要求解一个三对角线性方程组。具体来说,对于 n+1 个数据点,设 hᵢ = uᵢ₊₁ − uᵢ 为第 i 段的参数长度。记各数据点处的二阶导数值为 Mᵢ = f''(uᵢ)(未知)。C² 连续性条件和插值条件导出以下三对角系统:
hᵢ₅₁·Mᵢ₅₁ + 2(hᵢ₅₁+hᵢ)·Mᵢ + hᵢ·Mᵢ₊₁ = 6[(pᵢ₊₁−pᵢ)/hᵢ − (pᵢ−pᵢ₅₁)/hᵢ₅₁]
对于 i = 1, ..., n−1(内部数据点),这是一个 (n-1)×(n-1) 的三对角线性系统。加上自然端点条件 M₀ = Mₙ = 0,系统有唯一解。该三对角系统可以通过 Thomas 算法(一种针对三对角矩阵的特化高斯消元法)在 O(n) 时间内高效求解。系数矩阵是严格对角占优的,保证了解的数值稳定性。解出所有 Mᵢ 后,每段三次曲线的四个系数可以通过差分关系直接写出。
对于第 i 段,u ∈ [uᵢ, uᵢ₊₁]:
f(u) = Mᵢ·(uᵢ₊₁−u)³/(6hᵢ) + Mᵢ₊₁·(u−uᵢ)³/(6hᵢ)
+ (pᵢ/hᵢ − Mᵢ·hᵢ/6)·(uᵢ₊₁−u)
+ (pᵢ₊₁/hᵢ − Mᵢ₊₁·hᵢ/6)·(u−uᵢ)
上述分段表达式直接给出了每段曲线的显式形式——通过二阶导数值 Mᵢ(即弯曲"力矩"分布)完全确定了整条样条的几何形状。
想一想:自然三次样条的"最小弯曲能量"性质意味着什么?它为什么能产生视觉上最自然的平滑曲线?将它与物理样条的类比联系起来:一根弹性钢尺被固定在数据点处,并让它在其余位置自由弯曲——它自然会最小化其内部的应变能(弯曲能量)。这正是自然三次样条在做的事情。
生活类比:自然三次样条就像你将一根柔韧的薄木条依次卡在若干个图钉的钉帽下。木条会自动弯曲成一个平滑的形状——它不会有两个地方突然"折"出尖角,也不会在两个图钉之间无端地多绕一圈。这是因为物理系统自然地最小化了木条的弯曲应变能。自然三次样条在数学上做的是完全相同的事情。
Catmull-Rom 样条与 Cardinal 样条
除了自然三次样条外,图形学中还有一类重要的插值样条——Catmull-Rom 样条。与自然三次样条类似,Catmull-Rom 样条也是分段三次多项式,精确通过所有给定的数据点。但它采用不同的切线构造方法。
对于数据点序列 p₀, p₁, ..., pₙ,在 pᵢ 和 pᵢ₊₁ 之间的 Catmull-Rom 曲线段由四个相邻数据点 pᵢ₅₁, pᵢ, pᵢ₊₁, pᵢ₊₂ 决定。在 pᵢ 处的切线由中心差分近似:
mᵢ = (pᵢ₊₁ − pᵢ₅₁) / 2
这给出了 Catmull-Rom 样条的一个重要性质:切线完全由相邻数据点的位置自动生成——用户只需指定数据点位置,无需输入任何切线信息。这使得 Catmull-Rom 在关键帧动画和数据可视化中非常受欢迎。
Catmull-Rom 曲线的矩阵形式(第 i 段,连接 pᵢ 和 pᵢ₊₁):
f(u) = [1 u u² u³] · M_CR · [pᵢ₅₁ pᵢ pᵢ₊₁ pᵢ₊₂]ᵀ
其中 M_CR = (1/2) · [ 0 2 0 0 ]
[-1 0 1 0 ]
[ 2 -5 4 -1 ]
[-1 3 -3 1 ]
Cardinal 样条是 Catmull-Rom 样条的推广,引入了一个张力参数(tension)c ∈ [0, 1] 来控制切线的缩放:
mᵢ = (1−c) · (pᵢ₊₁ − pᵢ₅₁) / 2
当 c = 0 时退化为标准 Catmull-Rom(切线最大,曲线最"松");当 c = 1 时切线为零,曲线退化为分段线性。张力参数 c = 0.5 是常用的折中值。这允许设计者在"松"(可能产生overshoot)和"紧"(分段线性)之间连续调节。
想一想:Catmull-Rom 样条和自然三次样条都是插值样条,都是 C¹ 连续的(Catmull-Rom)或 C² 连续的(自然三次),它们各有什么优缺点?Catmull-Rom 每个数据点修改只影响 4 个相邻段(局部性更好),但只有 C¹ 连续性。自然三次样条是全局的(修改任何一个数据点改变整条曲线),但提供 C² 连续性。
Catmull-Rom 曲线的 4×4 矩阵可以通过 Hermite 形式的框架从四个控制点直接导出。设第 i 段曲线连接 pᵢ 和 pᵢ₊₁,使用四个相邻控制点 pᵢ₋₁, pᵢ, pᵢ₊₁, pᵢ₊₂。
第一步:确定 Hermite 条件。Catmull-Rom 的切线由中心差分给出:
mᵢ = (pᵢ₊₁ − pᵢ₋₁) / 2 在 pᵢ 处的切线 mᵢ₊₁ = (pᵢ₊₂ − pᵢ) / 2 在 pᵢ₊₁ 处的切线
这给出了 Hermite 条件的四个向量:起终点位置 pᵢ, pᵢ₊₁ 和起终点切线 mᵢ, mᵢ₊₁。
第二步:使用 Hermite 基矩阵。已知 Hermite 曲线的矩阵形式为:
f(u) = [1 u u² u³] · M_H · [pᵢ pᵢ₊₁ mᵢ mᵢ₊₁]ᵀ
其中 Hermite 基矩阵(约束矩阵的逆)为:
M_H = [ 1 0 0 0 ]
[ 0 0 1 0 ]
[-3 3 -2 -1 ]
[ 2 -2 1 1 ]
第三步:将切线用控制点的线性组合代替。将 mᵢ 和 mᵢ₊₁ 的定义代入,我们需要将 [pᵢ, pᵢ₊₁, mᵢ, mᵢ₊₁] 写成 [pᵢ₋₁, pᵢ, pᵢ₊₁, pᵢ₊₂] 的线性变换:
[pᵢ] [ 0 1 0 0] [pᵢ₋₁] [pᵢ₊₁] = [ 0 0 1 0] · [pᵢ ] [mᵢ] [-½ 0 ½ 0] [pᵢ₊₁] [mᵢ₊₁] [ 0 -½ 0 ½] [pᵢ₊₂]
第四步:矩阵乘法得到 Catmull-Rom 基矩阵。M_CR = M_H · T(其中 T 是上述变换矩阵):
M_CR = M_H · T
= [ 1 0 0 0] [ 0 1 0 0]
[ 0 0 1 0] · [ 0 0 1 0]
[-3 3 -2 -1] [-½ 0 ½ 0]
[ 2 -2 1 1] [ 0 -½ 0 ½]
= ½ · [ 0 2 0 0]
[-1 0 1 0]
[ 2 -5 4 -1]
[-1 3 -3 1]
这就是前面给出的 Catmull-Rom 基矩阵。因此,第 i 段 Catmull-Rom 曲线为:
f(u) = [1 u u² u³] · M_CR · [pᵢ₋₁ pᵢ pᵢ₊₁ pᵢ₊₂]ᵀ, u ∈ [0, 1]
验证插值条件:
f(0) = [1,0,0,0] · M_CR · [pᵢ₋₁, pᵢ, pᵢ₊₁, pᵢ₊₂]ᵀ = pᵢ ✓ f(1) = [1,1,1,1] · M_CR · [pᵢ₋₁, pᵢ, pᵢ₊₁, pᵢ₊₂]ᵀ = pᵢ₊₁ ✓
该推导体现了基矩阵方法的强大:通过矩阵乘法的层层组合(Hermite 基矩阵 × 切线控制点变换矩阵 = Catmull-Rom 基矩阵),我们可以从一种曲线类型推导出另一种。只需替换"切线如何从控制点计算"这一步即可获得不同的曲线类型。
Cardinal 样条通过张力参数 τ ∈ [0, 1] 泛化了 Catmull-Rom:
mᵢ = (1−τ) · (pᵢ₊₁ − pᵢ₋₁) / 2
张力参数 τ 的物理直觉来自弹性力学:想象四段弹簧连接四个质点的链——当 τ 增加时,相当于增大了弹簧的劲度系数,链变得更"紧":
张力参数提供了一个连续的控制旋钮——从松弛的自然弯曲到僵硬的折线——无需改变数据点位置。这使得 Cardinal 样条在交互设计中非常方便:设计师可以先放置关键点定义大致形状,然后全局调节 τ 来控制整体风格(更圆润还是更锐利)。
Catmull-Rom 样条在实时图形学和游戏开发中的广泛应用绝非偶然——其性质恰好匹配了交互式应用的几个核心需求:
一、相机路径平滑。游戏中的过场动画(cutscene)和自由视角需要相机沿平滑路径移动。设计师只需在场景中放置少量关键点("我想让相机从这里经过,再绕到那里"),Catmull-Rom 自动生成穿过所有关键点的 C¹ 连续路径。使用均匀弧长重参数化后,相机以恒定速度沿路径移动——不会在急弯处加速(这是 Catmull-Rom 作为插值曲线的天然优势)。
二、角色移动路径。在 RTS(即时战略)和 RPG 游戏中,单位的移动路径需要平滑处理。如果直接让单位沿 A* 导航网格生成的折线行走,拐弯处会出现生硬的 90 度转向。对导航路径折点序列使用 Catmull-Rom 插值,可以生成自然的弧形转弯——单位在接近拐点前就开始平滑转向,视觉上远更可信。关键是 Catmull-Rom 的局部性:如果环境变化导致路径中某个折点被移除/替换,只有该点附近的 4 段曲线需要重新计算——整个路径的其余部分不变。
三、关键帧动画插值。在三维动画软件(Maya、Blender)和游戏引擎(Unity、Unreal)中,动画师在时间轴上设置关键帧(3D 变换矩阵在特定时刻的值)。系统需要在关键帧之间生成连续的中间帧——这正是参数曲线插值的舞台。Catmull-Rom 的"自动切线"特性意味着动画师只需设置位置关键帧,切线(速度)自动由前后关键帧的中心差分产生——无需手动调整切线手柄。张力参数允许动画师在一个滑块上平衡"弹性感"和"机械精度"。
四、缓动曲线。Catmull-Rom 可以与缓动函数(easing functions)结合——先对数据点做 Catmull-Rom 空间插值,再用缓动函数重参数化时间轴。这样可以同时获得"空间上的平滑路径"和"时间上的加速/减速效果",这是现代 UI 动画的标配组合。
五、管线/绳索物理。在物理模拟中,绳索或管线的初始形状可以用 Catmull-Rom 样条定义——给定几个"锚点"(固定端点),中间段由 Catmull-Rom 生成初始几何。物理引擎接管后对这些"质点-弹簧"链进行动力学仿真。
在前面几节中,我们主要讨论了直接通过指定多项式系数或端点约束来控制曲线的方法。然而,在实际的图形学和CAD系统中,最常用的方法是使用逼近曲线——曲线不一定通过除端点外的所有控制点,而是被控制点"吸引"并形成平滑的形状。本节介绍三种最重要的逼近曲线族:Bézier 曲线、B 样条和非均匀 B 样条(包括 NURBS)。
Bézier 曲线是由法国工程师 Pierre Bézier 在1960年代为雷诺汽车公司开发的。其核心创新在于:用控制点的几何位置替代 Hermite 形式中抽象的切线向量,使得曲线设计变得直观且交互友好。Bézier 曲线是计算机图形学和CAD中最广泛使用的曲线形式。
Bernstein 多项式与 Bézier 定义
一条 n 次 Bézier 曲线由 n+1 个控制点 b₀, b₁, ..., bₙ 定义:
f(t) = Σᵢ₀ⁿ Bᵢⁿ(t) · bᵢ, t ∈ [0, 1] (15.9)
其中 Bᵢⁿ(t) 是 Bernstein 多项式(Bernstein polynomial),定义为:
Bᵢⁿ(t) = C(n, i) · tᵢ · (1 − t)ⁿ⁻ᵢ (15.10)
其中 C(n, i) = n! / (i! (n−i)!) 是二项式系数。Bernstein 多项式的核心性质包括:
Σ Bᵢⁿ(t) = 1 对所有 t 成立(由二项式定理 (t + (1−t))ⁿ = 1 证明)。Bᵢⁿ(t) ≥ 0 对所有 t ∈ [0, 1] 成立。Bᵢⁿ(t) = Bₙ₅ᵢⁿ(1−t)。Bᵢⁿ(t) = (1−t)·Bᵢⁿ⁻¹(t) + t·Bᵢ₅₁ⁿ⁻¹(t)。单位剖分 + 非负性意味着 Bézier 曲线上的每个点都是控制点的凸组合。因此,整条曲线始终落在其控制多边形的凸包之内——这是 Bézier 曲线最受设计师欢迎的性质:曲线永远不会"跑出"控制点围成的区域。
想一想:为什么凸包性质对交互设计如此重要?想象你在设计一个汽车外壳——你需要确保曲线不会意外地"刺穿"发动机舱或其他不该去的区域。凸包性质给了你一个硬保证:只要控制点在合理区域内,曲线就绝不会越界。
Bernstein 多项式 Bᵢⁿ(t) = C(n,i)·tⁱ·(1−t)ⁿ⁻ⁱ 是 Bézier 曲线的数学基石。其五条核心性质各自对应 Bézier 曲线的一个重要几何行为。以下是每条性质的完整证明:
性质一:非负性——Bᵢⁿ(t) ≥ 0 对所有 t ∈ [0, 1]。
证明:当 t ∈ [0, 1] 时,t ≥ 0 且 (1−t) ≥ 0。因此 tⁱ ≥ 0,(1−t)ⁿ⁻ⁱ ≥ 0,二项式系数 C(n,i) = n!/(i!(n−i)!) 为正整数。三个非负因子相乘,结果非负。■ 非负性保证了 Bézier 曲线上的每个点都是控制点的凸组合(结合下面的单位剖分性质),从而保证凸包性质。
性质二:归一化(单位剖分)——Σᵢ Bᵢⁿ(t) = 1 对所有 t。
证明:直接套用二项式定理:
Σᵢ₌₀ⁿ Bᵢⁿ(t) = Σᵢ₌₀ⁿ C(n,i)·tⁱ·(1−t)ⁿ⁻ⁱ = (t + (1−t))ⁿ = 1ⁿ = 1
这一性质至关重要:它保证了 Bézier 曲线对所有控制点做的是仿射组合,因此曲线具有仿射不变性(对控制点施加仿射变换,等价于对曲线施加同样的变换)。■
性质三:对称性——Bᵢⁿ(t) = Bₙ₋ᵢⁿ(1−t)。
证明:
Bₙ₋ᵢⁿ(1−t) = C(n, n−i) · (1−t)ⁿ⁻ⁱ · (1−(1−t))ⁿ⁻⁽ⁿ⁻ⁱ⁾
= C(n, n−i) · (1−t)ⁿ⁻ⁱ · tⁱ
= C(n, i) · tⁱ · (1−t)ⁿ⁻ⁱ (因为 C(n,n−i)=C(n,i))
= Bᵢⁿ(t)
对称性的几何含义:Bézier 曲线关于其控制点序列的逆序具有对称反射关系。也就是说,将控制点顺序反转(b₀,b₁,...,bₙ → bₙ,bₙ₋₁,...,b₀),得到的曲线完全相同,只是参数化方向相反。■
性质四:递推关系——Bᵢⁿ(t) = (1−t)·Bᵢⁿ⁻¹(t) + t·Bᵢ₋₁ⁿ⁻¹(t),其中 B₋₁ⁿ⁻¹ = Bₙⁿ⁻¹ ≡ 0。
证明:利用二项式系数的递推关系 C(n,i) = C(n−1,i) + C(n−1,i−1):
Bᵢⁿ(t) = C(n,i)·tⁱ·(1−t)ⁿ⁻ⁱ
= [C(n−1,i) + C(n−1,i−1)]·tⁱ·(1−t)ⁿ⁻ⁱ
= C(n−1,i)·tⁱ·(1−t)ⁿ⁻ⁱ + C(n−1,i−1)·tⁱ·(1−t)ⁿ⁻ⁱ
= (1−t)·C(n−1,i)·tⁱ·(1−t)ⁿ⁻¹⁻ⁱ + t·C(n−1,i−1)·tⁱ⁻¹·(1−t)ⁿ⁻ⁱ
= (1−t)·Bᵢⁿ⁻¹(t) + t·Bᵢ₋₁ⁿ⁻¹(t)
这个递推关系是 de Casteljau 算法的直接代数基础——它说明 n 次 Bernstein 基函数可以由两个 (n−1) 次基函数通过线性插值生成。递归应用这一关系便得到了 de Casteljau 的三角结构。■
性质五:端点插值——B₀ⁿ(0)=1, B₀ⁿ(1)=0; Bₙⁿ(0)=0, Bₙⁿ(1)=1; Bᵢⁿ(0)=Bᵢⁿ(1)=0 对 1 ≤ i ≤ n−1。
证明:直接代入 t=0 和 t=1。当 t=0 时,tⁱ = 0 对所有 i≥1,因此只有 i=0 的项 B₀ⁿ(0)=C(n,0)·0⁰·1ⁿ = 1 非零(0⁰=1 约定)。当 t=1 时,(1−t)ⁿ⁻ⁱ = 0 对所有 i Bézier 曲线的凸包性质——严格证明 凸包性质是 Bézier 曲线最重要的一项几何保证:曲线完全位于其控制点凸包内部。证明只需 Bernstein 多项式的非负性和单位剖分: 由于 Bᵢⁿ(t) ≥ 0 且 Σᵢ Bᵢⁿ(t) = 1,f(t) 是 {bᵢ} 的凸组合。凸组合的几何定义是:一组点的加权平均,其中所有权重非负且和为 1。所有凸组合的集合恰好等于这些点的凸包。因此 f(t) ∈ Conv{b₀, ..., bₙ} 对所有 t∈[0,1] 成立。 这一性质在碰撞检测和渲染中极为实用:如果控制点的轴对齐包围盒(AABB)不与某物体相交,则整条 Bézier 曲线也必定不与该物体相交。这使得我们可以用控制点包围盒作为曲线几何的保守且廉价的替代品,在粗筛阶段快速剔除不可能相交的情况。 Bézier 曲线的变差减少性质 变差减少性质(Variation Diminishing Property, VDP)陈述:任意直线与 Bézier 曲线的交点数 ≤ 该直线与曲线控制多边形的交点数。 用更直观的话说:Bézier 曲线的弯曲程度永远不会超过其控制多边形的弯曲程度。如果你画出控制点并用线段依次连接(控制多边形),这条折线代表了"最波浪"的可能形状。Bézier 曲线是折线的"平滑版"——任何一个方向的弯曲都不如控制多边形在该方向的弯曲来得剧烈。这意味着: VDP 的证明基于 Bernstein 多项式的全正性(totally positive)——具体而言,Bernstein 基函数矩阵 Bᵢⁿ(tⱼ) 的任意子行列式都非负。这使得 Bézier 曲线是控制点的"变差缩减"映射。这一数学性质在设计实践中高度实用:设计师可以通过观察控制多边形的形状来可靠地预测曲线的行为,而不必每次都画出整条曲线。 De Casteljau 算法为什么叫"角切割"算法 De Casteljau 算法之所以形象地被称为"角切割"(corner cutting),是因为它的每一步几何操作都是切掉控制多边形的一个"角":三角形 b₀b₁b₂ 的角在 b₁ 处被切掉(替换为 (1−t)b₀ + tb₁ 和 (1−t)b₁ + tb₂),产生一个"更圆润"的控制多边形。反复切角 → 控制多边形逐渐收缩 → 极限就是 Bézier 曲线。这正是 Chaikin 细分算法和一般细分曲面理论的基本思想来源。 生活类比:De Casteljau 算法就像一位雕塑家的工作流程。雕塑家从一块粗糙的立方体大理石(控制多边形)开始。第一轮:切掉每个角,得到一个更圆润的多面体。第二轮:再切掉新产生的角。经过足够多次"角切割",原本棱角分明的石块变成了光滑的雕塑——这就是 Bézier 曲线。参数 t 决定每次切割的深度(切得越深,收敛越快)。t=0.5 切得最均衡,通常用于细分渲染。 三次 Bézier 曲线 最高频使用的 Bézier 曲线次数是 端点性质: 这意味着切线方向由相邻控制点的连线自然给出——设计师只需要拖动控制点即可调整切线,而不需要显式输入切线向量。这是 Bézier 曲线在交互设计方面胜过 Hermite 的关键原因。 生活类比:Bézier 曲线就像是你在桌子上放四个磁铁(控制点),然后让一根弹性细链被这几个磁铁吸引。链子的两端被牢牢吸在 b₀ 和 b₃ 上,而 b₁ 和 b₂ 则像是"引导磁铁"——链子会朝着它们的方向弯曲,但不一定经过它们。拖动 b₁ 会改变起点的"出发方向",拖动 b₂ 会改变终点的"到达方向"。 Bézier 曲线的基矩阵 利用三项式展开,可以将三次 Bézier 曲线(15.11)写成矩阵形式。对应的基矩阵 因此曲线的矩阵表示为: 通过基矩阵,Bézier 曲线和 Hermite 曲线之间可以互相转换——它们只是同一条三次多项式曲线的不同表示。从 Bézier 控制点到 Hermite 条件的转换关系为: De Casteljau 算法 De Casteljau 算法是 Bézier 曲线理论的基石——它通过一连串优雅的线性插值来计算曲线上的点,完全不需要显式计算 Bernstein 多项式。 算法定义(n 次 Bézier 曲线,参数 经过 n 轮递推后,只剩下一个点 其中 生活类比:De Casteljau 算法就像一场接力赛。四个朋友站在操场上(b₀ 到 b₃)。裁判喊"朝你右边的人走 t 比例!"第一轮,每人走到朝向右边人的 t 比例位置,形成3个新位置。第二轮,新的3人继续走 t 比例,剩下2人。第三轮,最后2人走 t 比例,最终只剩1人。这个人的位置恰好就是 Bézier 曲线上 t 处的点!t = 0.5 时每人走一半,最终站在曲线的中点。 Bézier 曲线的细分 除了在 这是"细分"的真正威力:一次 de Casteljau 求值同时给出了精确的左右子曲线控制点。递归细分可用于曲线求交(Bézier Clipping)和自适应渲染: 想一想:De Casteljau 算法为什么能同时完成求值和细分?用数学归纳法验证:算法三角左边缘上的点确实构成了左半子曲线的控制点。这揭示了一个深层事实:Bézier 求值本质上是一个重复的线性插值过程,而每一次中间插值结果恰好对应着某一级子曲线的控制点。 Bézier 曲线的几何性质 Bézier 曲线有若干优良性质使其在设计和计算中特别有用: Bézier 曲线的局限性在于缺乏局部控制——移动任何一个控制点都会改变整条曲线的形状。这使得 Bézier 曲线在处理大量控制点时不够理想。这正是 B 样条要解决的问题。 Bézier 曲线的升阶 升阶(degree elevation)是将一条 从 其中约定缺失的旧控制点为 升阶可以反复执行。极限情况下(无限次升阶),控制多边形逐点收敛于 Bézier 曲线本身。注意升阶是精确的(形状完全不变),而降阶(degree reduction)通常是近似的——因为一般情况下无法用更低次的 Bézier 曲线精确表示一条高次曲线。 B 样条(B-spline,"Basis Spline"的缩写)将 Bézier 曲线推广到允许使用任意数量的控制点,同时保持局部控制性(每个控制点只影响曲线的一个局部区间)。B 样条由三个要素定义: 三者满足关系: B 样条为什么比 Bézier 更好——三大核心优势 B 样条不是 Bézier 的替代品,而是 Bézier 的"超级集合"——它将 Bézier 曲线的所有优良性质(凸包、变差缩减、端点插值)继承下来,同时解决了 Bézier 曲线的最大缺陷。以下是三大核心优势: 优势一:局部控制性——"改一处只动一片"。Bézier 曲线的控制点数严格等于次数+1。这意味着,如果你想用 10 个控制点来定义一条复杂的形状,你必须使用 9 次 Bézier 曲线——修改任何一个控制点都会改变整条曲线的形状。这是 Bézier 曲线最致命的实用性缺陷:设计师无法在不影响全局的情况下微调局部细节。B 样条通过引入节点向量,使得每个控制点 dᵢ 仅仅影响曲线的 (k+1) 个相邻节点区间段。具体来说,基函数 Nᵢ,ₖ(u) 在区间 [uᵢ, uᵢ₊ₖ₊₁) 之外恒为零——这一性质被称为局部支撑性(local support)。移动 dᵢ 只会改变曲线在该局部区间内的形状,其余部分完全不受影响。在工业设计中,这个性质可能是 B 样条相比 Bézier 最被珍视的优势——它允许设计团队对汽车外壳的不同区域独立地进行方案迭代。 优势二:控制点数独立于次数——"数量与复杂度解耦"。在 Bézier 曲线中,如果你指定了 20 个控制点,曲线的次数就是 19——无论你喜欢与否。高次多项式引入数值不稳定性和振荡(Runge 现象),而且计算成本随次数平方增长。B 样条优雅地斩断了这个联系:控制点数 n+1 和次数 k 是两个独立的参数。你可以用 100 个控制点和 3 次(三次)B 样条来构造一条极其复杂的曲线——每一段仍然只是简单的三次多项式,但整体可以表达极其丰富的形状。这就像用 100 段短直轨拼合出蜿蜒的铁道线——每段自身的复杂度不变,整体复杂度随段数线性增长而非指数增长。 优势三:天然的 Cᵏ⁻¹ 连续性——"拼接自动平滑"。在没有重节点的标准 B 样条中,k 次曲线的相邻片段会自动获得 Cᵏ⁻¹ 连续性。对于最常用的三次 B 样条(k=3),这意味着曲线在任何两个片段的拼接处都自然具有 C² 连续性(位置、切线、曲率全部连续)。而在 Bézier 曲线中,要实现两个三次片段之间的 C² 连续性,需要手工施加复杂的控制点约束(我们前面推导过)。B 样条把这个约束内化到了其数学结构中——只要用开放均匀节点向量构造曲线,Cᵏ⁻¹ 连续性就是天然的。 总结:Bézier 曲线适合"单段简单造型"(如字体中的一段轮廓),B 样条适合"多段复杂造型"(如汽车外壳的完整流线型曲面)。这不是哪个好哪个差的问题——而是各有适用场景。事实上,Bézier 曲线是 B 样条在节点向量=[0,...,0,1,...,1] 和 n=k 时的退化特例。 Cox-de Boor 递推公式 B 样条的基函数由 Cox-de Boor 递推公式定义: 其中约定 B 样条曲线定义为: 参数 想一想:Cox-de Boor 递推从"阶梯函数"(0次)开始,通过反复的线性插值式的递归构建出更高次的连续基函数。这与 de Casteljau 算法有什么本质联系?(提示:de Casteljau 可以看作 Cox-de Boor 在节点向量为 [0,0,0,0,1,1,1,1] 时的特殊情况。) Cox-de Boor 递推的完整逐级推导 为了更好地理解 B 样条基函数是如何从"台阶"一步步"磨光"为光滑函数的,下面给出从 0 次到 2 次的完整推导过程。以均匀节点向量 U=[0,1,2,3,4,5,...] 为例。 0 次基函数(分段常数)——最原始的"积木": 例如:N₂,₀(u) 在 u∈[2,3) 上为 1,在其他地方为 0。N₃,₀(u) 在 u∈[3,4) 上为 1。这些就是高度为 1、宽度为 1 的矩形脉冲——数学中最简单的"开关"函数。每个控制点 dᵢ 乘以 Nᵢ,₀(u),意味着曲线在 [uᵢ, uᵢ₊₁) 区间上等于 dᵢ——这产生了一条分段常数"曲线"(其实是离散的点集)。 1 次基函数(分段线性)——"帐篷函数": 将 0 次基函数代入 Cox-de Boor 递推公式(k=1),得到 Nᵢ,₁(u): 对于 u∈[uᵢ, uᵢ₊₁):Nᵢ,₀(u)=1, Nᵢ₊₁,₀(u)=0 → Nᵢ,₁(u) = (u−uᵢ)/(uᵢ₊₁−uᵢ),从 0 线性增长到 1。 对于 u∈[uᵢ₊₁, uᵢ₊₂):Nᵢ,₀(u)=0, Nᵢ₊₁,₀(u)=1 → Nᵢ,₁(u) = (uᵢ₊₂−u)/(uᵢ₊₂−uᵢ₊₁),从 1 线性下降到 0。 这就是著名的"帐篷函数"(hat function)——在 [uᵢ, uᵢ₊₂) 上非零,在 uᵢ₊₁ 处达到峰值 1。1 次 B 样条曲线 f(u) = Σ Nᵢ,₁(u)·dᵢ 是一条分段线性曲线(等同于控制多边形本身)。每个 u 只被两个非零基函数覆盖 → 每段直线由两个相邻控制点插值得到。 2 次基函数(分段二次)——三次连续性的"过渡带": 再次递推(k=2),Nᵢ,₂(u) 由 Nᵢ,₁(u) 和 Nᵢ₊₁,₁(u) 加权生成。在均匀节点下,其结果在 [uᵢ, uᵢ₊₃) 上由三段不同的二次多项式拼合而成——相邻片段在拼接处自动获得 C¹ 连续性。这个"从两个帐篷函数拼出一个二次钟形曲线"的过程展现了 Cox-de Boor 递推的核心机制:每一层递推 = 将上一层两个相邻的基函数做一次线性插值式的"融合",产生一个支集更宽、连续性更高的新基函数。 3 次基函数——最常用的"C² 连续性"基函数: 继续递推(k=3),得到三次 B 样条基函数——支集跨度为 4 个节点区间,内部由四段不同的三次多项式拼成,在拼接处达到 C² 连续性。这就是工业界最常用的三次 B 样条:4 个控制点决定一段曲线,相邻段共享 3 个控制点(滑动窗口),曲线整体 C² 连续。 从 0 次"台阶"→1 次"帐篷"→2 次"钟形"→3 次"C² 钟形",这个逐级"磨光"的过程完美展示了 Cox-de Boor 递推如何将最粗糙的分段常数函数"打磨"为光滑的 B 样条基函数。每一步递推在代数上是两个相邻基函数的线性插值,在几何上是将控制多边形的一个"角"切掉——最终极限就是光滑的 B 样条曲线。 节点向量是 B 样条的"控制面板"——通过调整节点的分布和重数,可以在不改变控制点位置的情况下精细控制曲线的形状和连续性。节点向量的三种类型各有其适用场景: 一、均匀节点向量(Uniform Knot Vector) 所有相邻节点的间隔相等:uᵢ₊₁ − uᵢ = 常数。最常见的均匀节点向量是 [0,1,2,3,4,...]。均匀 B 样条的计算最简单(所有除式中的分母都相同),但其一个显著特性是:曲线不通过首尾控制点。这是因为首尾节点的重数不足——曲线在起点附近需要 k+1 个控制点来"锚定"位置,均匀节点前 k 个节点区间上基函数不全。均匀节点向量主要用于理论分析和周期性闭合曲线(此时首尾连接通过周期节点向量实现)。 二、开放均匀节点向量(Open Uniform / Clamped Knot Vector) 首尾 k+1 个节点重复(等于端点值),中间节点均匀分布。例如三次 B 样条:U = [0,0,0,0, 1,2,3, ..., m−2k, m−2k, m−2k, m−2k]。首尾重复节点使得 B 样条基函数在首尾端点处退化到类似 Bernstein 多项式的行为——N₀,ₖ(0)=1、Nₙ,ₖ(1)=1,曲线因此精确通过首尾控制点。这是实际应用中最常用的节点向量类型——它结合了 B 样条的局部控制性和 Bézier 的端点插值行为。大多数 CAD 系统中的默认 B 样条就是这个配置。 三、非均匀节点向量(Non-uniform Knot Vector) 节点间隔不相等,可以在任意位置设置重复节点。非均匀分布的主要用途包括:(1) 在需要更多细节的区域(高曲率区域)使用更密集的节点——更多的节点区间意味着更多的控制点影响力在该区域汇聚,提供了更高的形状灵活性;(2) 通过在某个位置增加节点重数来局部降低连续性——例如,在三次 B 样条中将一个内部节点的重数从 1 增加到 3,会在该节点位置产生一个尖锐的角点。非均匀节点向量是 NURBS 命名中 "NU"(Non-Uniform)的来源。 重节点对连续性的精确影响: 这个"重数↔连续性"的精确映射是 B 样条设计的核心工具:设计师可以通过在关键位置插入重节点来引入角点,而不必切换到不同的曲线类型。这远比在 Bézier 曲线中通过将两个片段首尾拼接来"制造"角点优雅得多。 节点向量的类型 开放均匀节点向量使 B 样条曲线通过首尾控制点——这是实际应用中最常见的选择。当节点向量为 B 样条的核心性质 重复节点的妙用 通过在节点向量中增加节点重数,可以局部降低连续性,甚至创造角点。对于三次 B 样条(k=3): 这种通过节点重数精确控制连续性的能力是 B 样条相比其他曲线形式的独特优势。 Cox-de Boor 递推的显式示例——三次均匀 B 样条 对于三次均匀 B 样条( 可以验证这四个基函数在 下一段曲线( 标准的 B 样条允许任意的节点间隔——这就是"非均匀"(nonuniform)的含义。非均匀节点分布在实践中非常重要,因为它允许我们在曲线需要更多细节的区域(如高曲率区域)分配更多的控制点和更细的节点间距。 NURBS——非均匀有理 B 样条 NURBS(Non-Uniform Rational B-Spline)是 B 样条的有理推广,也是现代工业标准的核心格式(IGES、STEP)。NURBS 的定义为: 其中 NURBS 的统一性和灵活性使其成为工业标准。在一个 NURBS 系统中,你可以用同一个数学框架表示从简单的直线段到复杂的自由形态曲面的一切——这是它的核心价值主张。 NURBS 精确表示圆锥曲线 NURBS 的"杀手级应用"是精确表示圆锥曲线。以四分之一圆弧为例(单位圆的第一象限),可以用一条三次 NURBS(k=3)精确表示: 对于一般角度 想一想:为什么 NURBS 而不是其他曲线形式成为工业标准?考虑数据交换的场景:如果每个CAD系统都使用自己独特的曲线表示,将设计从一个系统传输到另一个系统就需要复杂的转换(可能引入误差)。NURBS 作为一个"通用语言"解决了这个问题——它既有足够的表现力来涵盖所有实际需要的形状,又足够标准化以实现可靠的互操作。 生活类比:NURBS 之于曲线/曲面设计,就像PDF之于文档。不同的人用不同的软件(Word、Pages、LaTeX)创建文档,但最终都输出为PDF来确保任何人看到的格式一致。类似地,不同的CAD软件可能内部使用不同的曲线表示,但通过IGES/STEP这样的NURBS格式进行数据交换时,几何信息得以完整保留。NURBS的"有理"部分(权重)就像是给每个控制点配了一个"引力强度"旋钮——可以精确地调出完美的圆弧和椭圆弧。 关于三次 Bézier 曲线与三次 B 样条的关系,一个重要的统一视角是:三次 B 样条可以看作是多段三次 Bézier 曲线在 C² 连续性条件下的拼接表示。通过节点插入(knot insertion),我们可以将 B 样条转换为等价的 Bézier 分段表示——这在 CAD 数据交换中频繁使用。反之,通过施加连续性约束,可以将多个 Bézier 曲线段合并为单个 B 样条表示。 有理 Bézier 曲线 与 NURBS 类似,Bézier 曲线也有有理形式。有理 Bézier 曲线给每个控制点附加一个权重,能以多项式 Bézier 无法做到的方式精确表示圆锥曲线。一条 对于二次有理 Bézier( Bézier 曲线 ↔ B 样条曲线转换 Bézier 曲线可以自然地嵌入 B 样条框架中。一条 Bézier → B 样条转换:将单段 Bézier 的控制点视为 B 样条控制点,节点向量设为极端的开放均匀形式。如需嵌入更大的 B 样条(更多控制点),通过节点插入在中间添加节点并更新受影响的控制点。 B 样条 → Bézier 转换:在每段多项式片的边界处反复插入节点,直至所有内部节点的重数达到 这种双向可转换性意味着任何支持 B 样条的系统都可以无缝兼容 Bézier 曲线——只需在导入/导出时执行适当的节点插入或节点移除操作。 Boehm 节点插入算法 在 B 样条中插入一个新节点而不改变曲线的几何形状是可能的——这是 B 样条的另一个关键能力。给定一条 只有 节点插入的实用价值包括: NURBS = B 样条 + 权重——最简洁的解释 NURBS 的数学本质可以用一句话概括:NURBS 是 B 样条在齐次坐标中的投影。将每个三维控制点 (xᵢ, yᵢ, zᵢ) 提升到四维齐次空间: 在四维空间中用标准(多项式)B 样条对这些提升点进行插值,得到四维曲线 F̂(u)。然后将结果投影回三维——对前三个分量除以第四个分量 w(u): 其中 X(u), Y(u), Z(u), w(u) 都是多项式,但它们的比值是有理函数——由此得名"有理"(Rational)。 这个框架的妙处在于:所有的多项式 B 样条理论(Cox-de Boor 递推、节点插入、局部支撑性、凸包性质)都可以在四维齐次空间中直接使用,无需修改。唯一的额外开销是在最后做一次齐次除法(透视除法)。权重 wᵢ 的作用就是改变控制点在"第四维"的坐标,从而在投影回三维时产生非线性效果——这种效果恰好能覆盖所有圆锥曲线。 为什么 NURBS 能精确表示所有圆锥曲线 前面已在有理 Bézier 中展示了圆弧的构造,这里给出更完整的解释。NURBS 能精确表示圆锥曲线,根源在于任意圆锥曲线都可以表示为二次有理参数形式——这是射影几何的基本结论。 在齐次视角下,一条二维圆锥曲线等价于三维空间中的一条二次多项式曲线经过透视投影。具体机制如下: 权重 w₁ 本质上控制的是"第四维的凸起高度"——想象控制多边形在四维空间中是一块"布",提升后的点离投影中心的远近决定了投影后曲线的弯曲程度。w₁ = cos(θ/2) 恰好使得投影后产生圆弧——这不是巧合,而是射影几何中"圆锥曲线是圆的透视投影"这一经典定理的直接应用。 NURBS 在工业中的绝对主导地位 NURBS 不是一个"可选方案"——它是现代 CAD/CAM/CAE 产业的必需格式。以下事实说明了其地位: 一、国际标准的强制格式。两个最核心的工业几何数据交换标准——IGES(Initial Graphics Exchange Specification,美国标准)和 STEP(Standard for the Exchange of Product model data,ISO 10303)——都将 NURBS 作为曲线和曲面的核心表示格式。任何希望参与供应链协作的 CAD 系统都必须支持导入/导出 NURBS 数据。福特和丰田的设计文件——从车身外壳到发动机进气道——全部以 NURBS 格式存储和流转。 二、AutoCAD、Rhino 和 CATIA 的内核。Rhino 3D 的标志性特色就是"以 NURBS 为原生格式"——它的一切建模操作都直接在 NURBS 数学上进行。AutoCAD 的样条实体内部使用 NURBS。Dassault Systèmes 的 CATIA(航空/汽车工业的标准 CAD 平台)深度依赖 NURBS。甚至连电影 VFX 中的 NURBS 曲面(Maya 的 NURBS 建模工具)也是同一套数学框架。 三、NURBS 的统一表示能力——"一种格式覆盖所有需求"。这是 NURBS 成为标准的关键原因。在一个 NURBS 框架内,你可以表示:
- 直线段(k=1,权重均为 1)
- 圆弧/椭圆弧(权重的精确配置)
- 自由形态曲线(设计师拖动控制点)
- Bézier 曲线(开放均匀节点 + n=k)
不需要在不同类型之间切换或转换。这种统一性对软件开发者来说意味着只需实现一套核心算法(Cox-de Boor 递推 + 节点插入 + 齐次除法),就能处理所有曲线相关功能。 四、为什么 NURBS 而不是细分曲面或 Bézier?虽然 Pixar 的 RenderMan 使用细分曲面,虽然 Adobe Illustrator 使用 Bézier 曲线——但在"零部件级别的精确几何"这个领域,NURBS 是没有对手的。原因是:(1) 细分曲面难以表达尖锐折痕和工程特征(螺纹、倒角);(2) Bézier 无法精确表示圆——而工程图纸上到处都是圆;(3) NURBS 明确地区分了"设计意图"(控制点和权重)和"制造精度"(节点密度控制公差)——前者是设计师的艺术,后者是工程师的精度要求。在一个统一的数学框架内调和这两者是 NURBS 不可替代的价值。 本章系统介绍了计算机图形学中曲线的理论基础与实用技术。我们从曲线的三种数学表示出发,深入讨论了参数化、重参数化和弧长参数化的概念。在此基础上,我们学习了多项式的分段表示方法——这是图形学中构造复杂曲线的基本策略。 连续性是衡量拼接曲线质量的核心概念。C⁰、C¹、C² 参数连续性要求导数在拼接点处完全相等;而 G¹、G² 几何连续性则只要求几何形状平滑过渡,为设计者保留了更大的自由度。 多项式曲线片——尤其是一、二、三次——是图形学中最基本的构造模块。三次多项式凭借其在低振荡、足够自由度和计算简洁性之间的完美平衡,成为了图形学中的"黄金次数"。通过基矩阵和混合函数的概念,我们将不同控制接口(Hermite、Bézier、Catmull-Rom)统一在同一个代数框架内。 Bézier 曲线凭借其直观的控制点接口和 de Casteljau 算法的优雅计算方式,成为了交互式曲线设计的事实标准。B 样条则通过引入节点向量,将 Bézier 的局部控制和局部凸包性质推广到任意数量的控制点上,并天然提供高阶连续性。NURBS 进一步加入了权重参数,使得圆锥曲线等有理曲线可以被精确表示——这一能力使其成为工业标准格式的基础。 以下表格总结了本章涵盖的主要曲线类型及其关键特性: 在掌握本章内容后,读者应当能够: 本章的内容为下一章(曲面,Surfaces)奠定了坚实的基础。曲面在本质上是在两个参数方向上组合曲线的结果——例如 Bézier 曲面片就是两个方向 Bézier 曲线的张量积(tensor product)。掌握了曲线,曲面就触手可及。 进一步阅读: 细分(subdivision)提供了一种与解析求值完全不同的曲线生成范式:它不是通过公式计算曲线上某个参数位置的点,而是通过反复地对控制多边形进行细化操作,使其逐渐收敛到一条光滑的极限曲线。细分方法的优雅之处在于:不需要高深的微积分——只需要线性插值——就能生成极其光滑的曲线。 George Chaikin 在 1974 年提出了一种简单的细分算法,可以从任意控制多边形生成二次 B 样条曲线。其规则极其简洁: 几何直觉:Chaikin 算法的每一步都是在每条边的 1/4 和 3/4 处"切掉"控制多边形的角。第一次切割后,原来的 n 个控制点变成了 2n 个新点;第二次切割后变成 4n 个;以此类推。每一步都使多边形更加"圆润"——就像一个雕刻家反复切削方石块的棱角,最终得到光滑的雕像。Chaikin 的极限曲线是一条 C¹ 连续的二次 B 样条曲线。 可以验证 Chaikin 算法经过无穷多次迭代后的极限 = 以原始控制点为 B 样条控制点的二次 B 样条曲线。这就是说,Chaikin 算法提供了二次 B 样条的另一种定义方式——一种完全基于几何切割、不涉及任何 Cox-de Boor 公式的构造方法。 de Casteljau 算法提供的细分与 Chaikin 有本质区别:它不是收敛到曲线的近似,而是在一次细分后产生两条与原始曲线完全重合的子曲线。 对于 n 次 Bézier 曲线,在参数 t 处应用 de Casteljau 算法后,三角形左边缘的控制点序列 [b₀, b₀¹, b₀², ..., b₀ⁿ] 精确地构成了定义在 [0, t] 上的左半 Bézier 曲线的���制点;三角形右边缘的控制点序列 [b₀ⁿ, b₁ⁿ⁻¹, b₂ⁿ⁻², ..., bₙ] 精确地构成了定义在 [t, 1] 上的右半 Bézier 曲线的控制点。两者拼接后与原曲线完全重合——没有近似误差。 这一性质的深层原因是:Bézier 曲线在 de Casteljau 的"角切割"操作下是不变的——控制点随切割变换,但曲线几何形状完全保留。这与 Chaikin 算法形成鲜明对比:Chaikin 的多边形在每一步后形状都在改变(逐步收拢到极限曲线),而 de Casteljau 的多边形在每步后仍然精确地表示同一条曲线。 在实践中,细分和解析求值往往是互补的而非对立的:先通过解析求值确定关键参数(例如交点的 t 值),然后使用 de Casteljau 细分将曲线拆分为子段——这种混合策略结合了两者的优势。 在 15.1.1 中我们介绍了弧长参数化的概念。本节将其发展为完整的实用技术——包括算法伪代码和实施细节。弧长重参数化是将任意参数曲线转化为"匀速"遍历曲线的过程,对于动画、纹理映射和均匀采样至关重要。 给定一条参数曲线 f(t), t∈[0,1],以下算法将其重参数化为近似弧长参数化 û(s),使得 |f'(û(s))| ≈ 常数。 输入:曲线 f(t),采样数 N(建议 N=曲线上控制点数的 10~20 倍)。 第一步:均匀采样并计算累积弧长。在参数区间 [0,1] 上均匀采样 N+1 个点 t₀=0, t₁=1/N, t₂=2/N, ..., t_N=1。计算每个采样点的弧长增量: 然后累积求和,得到每个采样点的累积弧长 Sᵢ: 总弧长 L = S_N。建立查找表:tᵢ ↦ Sᵢ(参数值 → 对应的累积弧长)。 第二步:对查找表做二分查找。对于任意归一化弧长 s ∈ [0, 1](目标弧长 = s·L),在查找表的 S 列中二分查找找到索引 i 使得 Sᵢ ≤ s·L < Sᵢ₊₁。 第三步:线性插值反求参数。在区间 [Sᵢ, Sᵢ₊₁] 上线性插值: 返回 û 作为弧长 s 对应的近似弧长参数。使用 û 代入原曲线 f,即得 f(û) ≈ 弧长参数化下的采样点。 输出:函数 g(s) = f(û(s)),其中 û(s) 由上述二分查找+线性插值给出。在区间 s∈[0,1] 上均匀递增 s,g(s) 以近似均匀的空间间距分布在曲线上。 该算法的精度取决于采样数 N。对于三次曲线,N≥100 通常已足够达到亚像素级精度。如果需要更高精度,可以在二分查找后使用一步 Newton-Raphson 精化(利用弧长积分的导数 = |f'(t)| 这一已知关系)。 在关键帧动画中,动画师在时间轴上设置关键帧(物体在某些时刻的位置/旋转/缩放)。系统在这些关键帧之间插值生成中间帧。如果参数化不是弧长的,那么物体在关键帧之间的运动速度将不均匀: 此外,弧长参数化还是"缓动函数"能够正常工作的前提。缓动函数(ease-in, ease-out)通过对时间参数 t 应用非线性映射 s = ease(t) 来实现加速/减速效果。如果底层的空间曲线本身已经是弧长参数化(均匀空间分布),缓动映射就能精确地产生预期的速度变化;如果底层参数化本身就速度不均,缓动效果会被叠加在已有的速度不均上,产生难以预测的复合效果。 弧长参数化在纹理映射中的一个重要应用是沿曲线均匀分布纹理坐标。考虑沿一条蜿蜒的道路或绳索贴上纹理——如果使用原始参数化,纹理在急弯处会被压缩(因为 |f'(t)| 较小 → 密集采样 → 纹理挤在一起),在平直处会被拉伸。弧长重参数化保证了纹理以均匀的空间密度分布,彻底解决了这种"拉伸-压缩"伪影。 具体实施:先对曲线做弧长重参数化(按上述算法建立查找表),然后将纹理坐标 u 直接映射到弧长 s(u=s·纹理重复次数/曲线总弧长)。对于每条纹理行,弧长参数化保证纹理沿曲线的密度恒定。 曲线拟合是数据分析、科学可视化和逆向工程中频繁使用的技术。它与插值的区别在于:拟合不要求曲线精确通过所有数据点,而是找到一条"最佳近似"曲线。 问题设定:给定 m 个数据点 (pⱼ)(j = 1, ..., m,通常是测量或扫描得到的),我们希望用 n+1 个基函数 φᵢ(t) 的线性组合来拟合这些点。拟合曲线形式为: 其中 cᵢ 是待定系数(向量),基函数 φᵢ(t) 可以选择单项式 {1, t, t², ..., tⁿ}(多项��拟合),或 Bernstein 基函数 {Bᵢⁿ(t)}(Bézier 拟合),或 B 样条基函数。 目标:最小化所有数据点到曲线的平方距离之和: 其中 tⱼ 是与每个数据点 pⱼ 相关联的参数值(需要预先选定——见下一节参数化的重要性)。 推导正规方程:将 E 对每个系数 cₖ 求偏导并令其为零: 引入矩阵记号:Φ 为 m×(n+1) 的基函数矩阵(Φⱼᵢ = φᵢ(tⱼ)),P 为 m×d 的数据矩阵(每行是一个 d 维数据点),C 为 (n+1)×d 的系数矩阵。正规方程在矩阵形式下为: 这是一个 (n+1)×(n+1) 的线性系统(对每个空间维度求解相同系统的不同右端项)。求解该线性系统即得最优系数矩阵 C*。通常 n ≪ m(基函数个数远少于数据点数),这使得 (ΦᵀΦ) 是一个小规模的正定对称矩阵——可以用 Cholesky 分解高效求解。 用 Bézier 基函数拟合:如果选择 φᵢ(t) = Bᵢⁿ(t)(Bernstein 多��式),那么解出的系数 cᵢ 直接就是 Bézier 曲线的控制点。这意味着"最小二乘 Bézier 拟合"等价于求解上述线性系统——不需要任何迭代或启发式搜索。 参数值 tⱼ 的分配方式是对拟合质量影响最大的单一决策——其重要性常被初学者低估。主要有三种参数化策略: 一个直观对比:对于一组在圆弧上密集采样的点,均匀参数化产生的拟合曲线会在弧的两端过冲(因为端点附近 |f'(t)| 大但 t 增长慢);弦长参数化产生的拟合曲线则平滑地贴近弧线。质量差异可达数十个百分点(RMS 误差)。 拟合的本质是在偏差和方差之间做妥协——用通俗的话说,是"贴合度"和"光滑度"之间的权衡: 实践中的经验法则:对于 CAD 逆向工程(从扫描点云重建曲线),m ≈ 10·(n+1) 是一个良好的起点——每个控制点由大约 10 个数据点支撑。如果数据噪声大,减少 n(使用更少控制点);如果数据精确(如来自解析函数),可以适当增加 n。交叉验证(留出一部分数据点不参与拟合,用它们测试拟合误差)是选择 n 的黄金标准。 插值(interpolation)与拟合不同:它要求曲线精确通过所有给定的数据点。虽然前文(15.3.6)已经介绍了 Lagrange 插值的基本概念,本节深入讨论其在实际中的致命缺陷以及更实用的替代方案。 Lagrange 插值给出了通过 n+1 个点的唯一 ≤n 次多项式。从纯数学角度看,这是完美的——唯一性、存在性、封闭形式。但从数值计算和工程角度看,高阶 Lagrange 插值是一场灾难。 Runge 现象:考虑一个简单的测试函数 f(x) = 1/(1+25x²) 在区间 [−1, 1] 上等距分布 11 个数据点。Lagrange 插值多项式在这些点之间剧烈振荡——在区间端点附近,插值多项式的误差可以比原始函数值大数十倍!这绝非因为函数本身怪异——1/(1+25x²) 在 [−1, 1] 上是无限光滑的。 根本原因:等距节点的 Lagrange 插值的 Lebesgue 常数(即插值算子范数)随 n 指数增长。这意味着数据中极小的��动(或舍入误差)会被插值过程指数放大——数据误差为 ε,插值误差可达 ε×2ⁿ。 为什么图形学几乎不用纯 Lagrange 插值:(1) Runge 现象使得高阶插值曲线在数据点之间不可预测地振荡;(2) 全局依赖性——移动任何一个数据点都会改变整条曲线(与 B 样条的局��性形成鲜明对比);(3) 数值不稳定性——对于 n>20 的插值,双精度浮点也无法保证可靠性。因此图形学中几乎总是用分段低次插值(样条)替代单一高次插值多项式。 两种端点条件的选择对样条的整体形状有极大的影响,尤其是在靠近端点的那一两段曲线中: 在实践中,如果你不确定端点处的切线值,自然端点条件是安全而合理的默认选择。如果你需要精确控制首尾处的切线方向(例如连接两段样条时),夹持条件提供这种控制。 插值(Interpolation)和逼近(Approximation / Fitting)代表了对"曲线如何与数据关联"的两种哲学: 一个关键的工程判断:如果你的数据来自精确的来源(如用户手动放置的锚点),且每个锚点都代表了设计师的意图——用插值(Catmull-Rom 或自然样条)。如果你的数据来自传感器/扫描仪,包含测量噪声——用逼近(Bézier 拟合或 B 样条拟合),让曲线"滤掉"噪声。 掌握了曲线,就具备了学习曲面的所有数学工具。曲面在本质上是一条曲线在另一个参数方向上的"扫描"——这种"曲线×曲线"的结构正是张量积(tensor product)的核心思想。 一条 Bézier 曲线在一个参数方向 u 上使用了 Bernstein 基函数 Bᵢᵐ(u) 对控制点做加权和。如果我们将控制点本身也变成一条参数 v 方向上的 Bézier 曲线——即每个"控制点"bᵢ(v) 是 v 的 Bézier 曲线——那么我们就得到了一个双参数曲面: 其中 pᵢⱼ 是 (m+1)×(n+1) 的控制网格(control mesh)。 为什么叫"张量积"?因为基函数是两个方向的 Bernstein 基函数的乘积:Bᵢᵐ(u) · Bⱼⁿ(v)。这个乘积定义了 (m+1)×(n+1) 个二元基函数,它们在 u 和 v 方向上分别具有 Bézier 曲线的所有性质。从线性代数的角度看,这等价于对基函数矩阵做 Kronecker 积——两��一维基的"外积"产生了二维基。 张量积的优雅之处在于:曲面的几乎所有计算都可以通过"逐行再逐列"(或逐列再逐行)的两次一维 de Casteljau 求值来完成。具体来说:
1. 固定 v,对每一行控制点用 u 方向 de Casteljau 求值 → 得到一条 u 方向曲线上的点。
2. 对步骤 1 的结果(在不同 v 处的点),用 v 方向 de Casteljau 求值 → 得到曲面上的点 S(u,v)。 这种"先求一个方向再求另一个方向"的策略将二维曲面求值简化为两次一维曲线求值——代码复用、效率高、数值稳定。 最常用的 Bézier 曲面是双三次片(m=n=3),由 4×4=16 个控制点 pᵢⱼ 定义(i=0,1,2,3; j=0,1,2,3)。这 16 个点按 4×4 网格排列: 双三次 Bézier 曲面片的 16 个控制点提供了强大的局部控制能力:设计师可以独立调整四条边界(通过边界控制点)、四个角点处的切线方向(通过相邻控制点)以及内部凸起程度(通过内部四点)。这 16 点参数化是几乎所有 CAD 曲面建模系统的基础构建块。 当两个 Bézier 曲面片共享一条边界时,G¹ 连续性(切线平面连续)的数学条件是共享边界两侧的控制点必须满足一定的共面关系。设两曲面片 F(u,v) 和 G(u,v) 沿边界 v=1(F)和 v=0(G)拼接: G¹ 连续性要求:对于边界上的每一点,两个曲面片的切线平面重合。这个条件转化为:控制点必须满足 其中 α>0 和 β 是常数(对所有 i 相同)。这个条件的几何解释是:G 的第二行控制点必须位于由 F 的最后两行控制点决定的"切线条带"内——具体来说,(pᵢ,ₙ₋₁, pᵢ,ₙ, qᵢ,₁) 四元组必须共面,且这个"共面关系"在沿边界移动时保持一致。 在实际设计中,这意味着要保证两个曲面片之间的 G¹ 连续并非简单地将边界控制点对齐——还需要额外约束一对内侧的控制点行。 曲线求交和点-曲线距离是几何处理中的基本运算,在碰撞检测、布尔运算和射线追踪中无处不在。本节介绍两种核心算法。 Bézier 裁剪是一种利用 Bézier 曲线的凸包性质快速定位两条曲线交点的方法。其核心思想是"递归排除"——先快速排除不可能相交的区域,再在剩余区域中精细搜索。 算法流程: 为什么高效?凸包排除是 O(1) 的(只需比较几个盒边界)。如果两条曲线只有一两个交点,绝大多数递归分支会在步骤 2 中被快速剪枝(prune)——实际计算量远小于暴力细分。Bézier 裁剪的复杂度接近于 O(log(1/ε))(ε 是精度要求),而非暴力方法的 O(1/ε)。 实用技巧:(1) 使用轴对齐包围盒(AABB)而非一般凸包——AABB 相交检测只需 6 次比较,远比一般凸包相交检测快;(2) 在每次递归前引入"胖零"(fat zero)——将 AABB 略扩大 ε 以避免因浮点舍入误差错过真实交点;(3) 对于高次曲线,先降阶(degree reduction)再用裁剪——低次曲线的 AABB 更紧致,排除效率更高。 给定一个空间点 Q 和一条参数曲线 f(t),求曲线上距离 Q 最近的点。这等价于最小化距离平方函数: 最小值出现在导数为零处:D'(t) = 2(f(t) − Q)·f'(t) = 0。这是一个关于 t 的非线性方程(一般情况下),通常用 Newton-Raphson 迭代求解。 Newton-Raphson 迭代步骤: 其中: 初始猜测 t₀ 的选择至关重要:一个好的初值可以保证快速收敛,一个坏的初值可能收敛到局部最小值(而非全局最小值)。通常策略: 收敛条件:|D'(tₖ)| < ε(ε≈10⁻⁸ 用于单精度,10⁻¹² 用于双精度),或 |tₖ₊₁−tₖ| < δ(δ≈10⁻⁶ 参数精度)。一般情况下,好的初值使 Newton 法在 3-5 次迭代内收敛到机器精度(二次收敛速率)。 陷阱:Newton 法可能发散(远离真实根)如果初值太差或 D''(t) 太小(曲线上几乎平直的区域)。健壮的实现应包含回退策略——如果迭代后 D(t) 反而增大了,回退到采样法并尝试相邻区域。 曲线理论的重要性不在于其数学优雅性本身,而在于它在现代图形学中无处不在的实际应用。本节挑选三个最具代表性的应用领域,展示曲线理论如何从教科书"落地"到真实的系统和产品中。 字体技术中的 Bézier 曲线选择��曲线工程决策的经典案例: 一个开放字体的轮廓是如何组成的?以字母"O"为例:外层轮廓由 4 段三次 Bézier 曲线组成(每段大约覆盖 90 度),内层轮廓同样 4 段。8 段三次 Bézier × 4 个控制点 = 32 个控制点定义了整个字母"O"。在渲染时,通过自适应 de Casteljau 细分将 Bézier 曲线转化为像素分辨率的折线段(通常 16-64 段每条边),然后填充。这一方案自 1980 年代沿用至今——现代 GPU 加速下,字符渲染的瓶颈已不再是 Bézier 求值,而是纹理缓存和像素填充率。 游戏引擎中几乎所有"平滑运动"的底层数学模型都是参数曲线。不同曲线类型在不同场景中各有优势: 关键帧动画的底层实现:动画师在时间线上设置了若干关键帧 (tₖ, pₖ)(其中 pₖ 是 3D 变换矩阵/四元数),系统在每个时间段 [tₖ, tₖ₊₁] 内使用 Catmull-Rom(或样条)插值生成中间帧。对于平移分量,使用 Catmull-Rom 空间插值;对于旋转分量,使用球面线性插值(slerp)+ Catmull-Rom 的速度重参数化。这是 Unity 和 Unreal 引擎中动画系统的标准架构。 一个典型的工业设计工作流清晰展示了曲线如何从设计师的意图"流动"到最终制造的产品: 阶段 1:概念草图 → 控制点建模。设计师在 Rhino 或 Alias 中通过拖动 NURBS 的控制点来塑造产品的外形(汽车外壳、手机边框、飞机机翼截面)。这个阶段的核心是"试错-迭代"——设计师通过视觉反馈反复调整控制点位置和权重,直到满足美学和功能要求。 阶段 2:工程约束注入。工程师对 NURBS 曲面添加约束——边界连续性(G¹/G² 与相邻部件衔接)、厚度约束(外壳不能薄于 X 毫米)、��率约束(反射不能有折痕)。通过调节节点向量中的重节点来在特定位置引入尖锐特征(如进气格栅边缘)。 阶段 3:公差分析与节点细化。在 NURBS 曲面上进行曲率分析(曲率梳图、斑马条纹、环境图映射),识别不连续区域。通过节点插入在需要更多细节的区域增加控制点密度——这在不改变整体形状的情况下赋予了局部微调的自由度。 阶段 4:三角剖分导出。CAD 曲面最终需要被渲染(可视化)或制造(CNC/3D 打印)。渲染管道需要三角形——因此 NURBS 曲面被导出为三角网格。这个过程称为"曲面细分"(tessellation):在参数空间 (u,v) 上放置均匀或自适应的采样网格,对每个网格顶点用张量积 de Casteljau/Cox-de Boor 求值得到三维点,然后连接成三角形。自适应细分在高曲率区域使用更密集的三角形,在平坦区域使用更稀疏的三角形——平衡了渲染质量与三角形预算。 阶段 5:物理制造。CNC 机床读取 NURBS 数据(通过 STEP 格式),将其转化为刀具路径——刀具沿 NURBS 曲面的等参线(u=常数或 v=常数)移动,逐层切削材料。NURBS 的精确数学定义确保了 CAD 屏幕上的设计形状与 CNC 成品的物理形状之间的误差在微米级别——这是制造业对数学模型精确性的终极要求。 题目:对于控制点为 b₀=(0,0), b₁=(2,4), b₂=(6,4), b₃=(8,0) 的三次 Bézier 曲线,用 de Casteljau 算法计算 t=0.5 处的点,并给出 t=0.5 剖分后左右子曲线的控制点。 解答:
第0层:b₀=(0,0), b₁=(2,4), b₂=(6,4), b₃=(8,0)。
第1层(t=0.5线性插值):
b₀¹ = 0.5(0,0)+0.5(2,4) = (1,2)
b₁¹ = 0.5(2,4)+0.5(6,4) = (4,4)
b₂¹ = 0.5(6,4)+0.5(8,0) = (7,2)
第2层:
b₀² = 0.5(1,2)+0.5(4,4) = (2.5,3)
b₁² = 0.5(4,4)+0.5(7,2) = (5.5,3)
第3层:
b₀³ = 0.5(2.5,3)+0.5(5.5,3) = (4,3) = f(0.5)。
左半子曲线控制点:(0,0), (1,2), (2.5,3), (4,3)。
右半子曲线控制点:(4,3), (5.5,3), (7,2), (8,0)。 题目:已知 Hermite 曲线端点 p₀=(0,0)、p₁=(3,2) 和切线 m₀=(2,4)、m₁=(4,−1)。将其转换为等价的 Bézier 形式,求四个控制点。 解答:
b₀ = p₀ = (0,0)
b₃ = p₁ = (3,2)
b₁ = p₀ + m₀/3 = (0+2/3, 0+4/3) = (2/3, 4/3)
b₂ = p₁ − m₁/3 = (3−4/3, 2−(−1/3)) = (5/3, 7/3)
验证:f'(0) = 3(b₁−b₀) = (2,4) = m₀ ✓;f'(1) = 3(b₃−b₂) = (4,−1) = m₁ ✓。 题目:计算椭圆 f(t) = (a cos t, b sin t), a>b>0 在 t=π/2 处的曲率(顶点 (0,b) 处)。 解答:
f'(t) = (−a sin t, b cos t),f''(t) = (−a cos t, −b sin t)
在 t=π/2:f' = (−a, 0),f'' = (0, −b)
|f'|³ = a³
二维叉乘(行列式):(−a)(−b) − (0)(0) = ab
κ = ab / a³ = b / a²
验证:a=b(圆)时 κ = a/a² = 1/a(圆的曲率)。顶点处椭圆的曲率小于同宽度的圆(更平坦)。 题目:用 Cox-de Boor 递推计算二次 B 样条(k=2)在均匀节点向量 U=[0,0,0,1,2,3,3,3] 下,N₁,₂(u) 在 u∈[0,1] 上的表达式。共有5个控制点。 解答:
节点向量:u₀=u₁=u₂=0, u₃=1, u₄=2, u₅=u₆=u₇=3。
对于 u∈[0,1](u₂=0 到 u₃=1):
0次基函数:N₂,₀(u)=1(在[0,1]上),其余为0。
N₁,₂(u) = [(u−u₁)/(u₃−u₁)]·N₁,₁(u) + [(u₄−u)/(u₄−u₂)]·N₂,₁(u)
需要先算 N₁,₁ 和 N₂,₁。通过递推可得在 [0,1] 上:
N₁,₂(u) = (1/2)(1−u)²(首段的二次B样条基函数)。 题目:两条三次 Bézier 曲线 f₁(控制点 a₀,a₁,a₂,a₃)和 f₂(控制点 b₀,b₁,b₂,b₃)在 a₃=b₀ 处拼接。写出 C¹ 和 G¹ 的完整条件。 解答:
C⁰:a₃ = b₀
C¹:a₃−a₂ = b₁−b₀ ⇒ b₁ = 2b₀−a₂(a₂,b₀,b₁共线且b₀为中点)
G¹:a₃−a₂ = k·(b₁−b₀), k>0(只要求共线,不要求中点)
C²:在C¹基础上增加 a₁−2a₂+a₃ = b₀−2b₁+b₂。 题目:证明:对于任意 n 次 Bézier 曲线,曲线上的任意点都位于其控制点的凸包内。这一性质的证明依赖 Bernstein 多项式的什么性质? 解答:
Bézier 曲线定义为 f(t) = Σ Bᵢⁿ(t) bᵢ。
Bernstein 多项式的两个关键性质:
(1) Bᵢⁿ(t) ≥ 0 对所有 t∈[0,1] 成立(非负性)。
(2) Σ Bᵢⁿ(t) = 1 对所有 t 成立(单位剖分,由二项式定理证明)。
因此 f(t) 是控制点 {bᵢ} 的凸组合。凸组合的定义保证 f(t) 落在 {bᵢ} 的凸包内。 题目:解释自然三次样条中"自然端点条件"(f''=0)的物理含义。如果你改为指定"夹持端点条件"(指定首尾一阶导数),在什么实际场景中这样做会有优势? 解答:
自然端点条件 f''=0 意味着曲线在两端不受弯矩——就像物理样条在两端没有被夹具夹住,而是自由延伸。这在外推性质上是合理的默认选择。
夹持端点条件在以下场景有优势:(1) 设计师需要精确控制曲线从特定方向"离开"起点;(2) 在动画路径中,需要指定物体在起点和终点的运动方向;(3) 当已知数据在端点处的一阶导数值(如来自物理测量)。 Q: 为什么不能用一条高次多项式代替多段低次多项式来画复杂曲线? A: 高次多项式(如10次以上)会出现严重的 Runge 现象——曲线在控制点之间剧烈振荡,即使控制点看起来"应该形成平滑曲线"。此外,(1) 高次多项式缺乏局部控制——修改任何一个系数都会改变整条曲线;(2) 高次多项式的系数在浮点运算中极易溢出或损失精度;(3) 计算效率低——求值需要更多乘法和加法。分段低次(尤其是三次)在数学稳定性、局部可控性和计算效率之间达到了最优平衡。 Q: Bézier 曲线和 B 样条曲线本质区别是什么?什么时候用哪个? A: Bézier 是 B 样条的特殊情形——当 B 样条的节点向量首尾 k+1 重时退化为 Bézier。核心区别:(1) Bézier 用单段多项式描述整条曲线(控制点数 = 次数+1),B 样条用多段拼接(控制点数远大于次数);(2) Bézier 内部无限可导但缺乏局部控制——移动任何控制点改变全部曲线,B 样条具有局部支撑性——每个控制点只影响 k+1 段;(3) Bézier 适合简单造型(如一段字体轮廓),B 样条/NURBS 适合大规模光滑曲面(如汽车外壳)。 Q: De Casteljau 算法除了求曲线上某一点的值,还能做什么? A: De Casteljau 算法是 Bézier 理论中的"瑞士军刀":(1) 细分——算法三角的左边缘点和右边缘点分别给出了左右子曲线的精确控制点,无需额外计算;(2) 求交计算——结合包围盒检测和递归细分,高效进行 Bézier Clipping;(3) 导数计算——中间层的差分结果可以用来计算任意阶导数;(4) 包围盒——控制点列的凸包提供了曲线的保守包围盒,用于碰撞检测和裁剪。 Q: 为什么汽车设计特别关注曲率连续性(G²),而字体设计只要求切线连续(G¹)? A: 源于两领域对"视觉缺陷"的敏感度差异。汽车外壳是高度反射的表面——曲率不连续会在周围景色的反射中产生清晰的"折痕",肉眼数米之外即可察觉(斑马条纹测试轻松检测)。字体通常尺寸较小、不具有镜面反射,G¹ 已保证边缘平滑无尖角——对人的视觉系统足够。高档字体可能追求更高连续性,但印刷和屏幕的固有分辨率限制使 G¹ 成为实用默认。 Q: 弧长参数化和普通参数化的区别是什么?为什么我们不总是用弧长参数化? A: 弧长参数化意味着 |f'(s)|=1——参数每前进一单位,实际路径也前进一单位。好处是均匀采样(固定 Δs 产生均匀间隔的采样点)且曲率公式简化为 κ=|f''(s)|。但问题在于:对绝大多数曲线(除直线和圆等特例外),弧长积分 ∫|f'(t)|dt 及其反函数 t(s) 没有解析表达式——这是"积分可数值计算但反函数不可解"的经典困境。实践中要么做"近弧长参数化"(让速率尽量均匀),要么用自适应采样补偿。 Q: 曲线的"曲率"和"二阶导数"有什么不同? A: 二者不是一回事。二阶导数 f''(t) 不仅反映弯曲程度,还受参数化快慢影响——即使沿直线不均匀加速,f'' 也可能非零。曲率 κ 是纯粹的几何量,与参数化完全无关:κ=|f'×f''|/|f'|³。分母的 |f'|³ 巧妙消除了参数化速度的影响。对于弧长参数化(|f'|=1),κ=|f''(s)|——此时二阶导数的大小才等于曲率。更直观地:κ=1/R,其中 R 是密切圆半径。 Q: NURBS 的"有理"部分(权重)到底起什么作用? A: 权重 wᵢ 给每个控制点附加了一个"引力强度"。wᵢ 越大,曲线在该控制点附近被"拉"得越近;wᵢ 趋近于0,该控制点的影响趋近于0。最关键的应用:通过适当选择权重,NURBS 可以精确表示所有圆锥曲线——圆、椭圆、双曲线、抛物线。标准 Bézier 和 B 样条(所有权重为1)只能逼近这些曲线。例如,用一条三次 NURBS 精确表示四分之一圆弧:只需设置 b₀, b₁, b₂ 为等腰直角三角形顶点,并令 w₀=1, w₁=cos(45°), w₂=1。f(t) = Σᵢ Bᵢⁿ(t)·bᵢ
n = 3。三次 Bézier 曲线由四个控制点 b₀, b₁, b₂, b₃ 定义:f(t) = (1−t)³·b₀ + 3t(1−t)²·b₁ + 3t²(1−t)·b₂ + t³·b₃ (15.11)
f(0) = b₀ 曲线通过第一个控制点
f(1) = b₃ 曲线通过最后一个控制点
f'(0) = 3(b₁ − b₀) 起点切线方向 = b₀ → b₁
f'(1) = 3(b₃ − b₂) 终点切线方向 = b₂ → b₃
M_B 为: [ 1 0 0 0]
M_B = [-3 3 0 0]
[ 3 -6 3 0]
[-1 3 -3 1]
f(t) = [1 t t² t³] · M_B · [b₀ b₁ b₂ b₃]ᵀ
p₀ = b₀, p₁ = b₃
m₀ = 3(b₁ − b₀), m₁ = 3(b₃ − b₂)
t ∈ [0, 1]):初始化:bᵢ⁰ = bᵢ (i = 0, ..., n)
递推: bᵢᵣ = (1 − t) · bᵢᵣ⁻¹ + t · bᵢ₊₁ᵣ⁻¹ (k = 1, ..., n; i = 0, ..., n−k)
b₀ⁿ = f(t)——这就是曲线上参数 t 处的点。例如对于三次 Bézier 曲线(n = 3):第0层: b₀ b₁ b₂ b₃
↘ ↘ ↘
第1层: b₀¹ b₁¹ b₂¹
↘ ↘
第2层: b₀² b₁²
↘
第3层: b₀³ = f(t)
bᵢ¹ = (1−t)bᵢ + t b₂₊₁,bᵢ² = (1−t)bᵢ¹ + t bᵢ₊₁¹,等等。t = 0.5 处细分外,de Casteljau 算法可以在任意参数 t 处给出精确的细分结果。对于 n 次 Bézier 曲线,在参数 t 处细分后:左半子曲线 ([0, t])控制点:
lᵢ = b₀ᵢ (i = 0, 1, ..., n)
(即 de Casteljau 三角左边缘的点)
右半子曲线 ([t, 1])控制点:
rᵢ = bᵢⁿ⁻ᵢ (i = 0, 1, ..., n)
(即 de Casteljau 三角右边缘的点)
n 次 Bézier 曲线表示为 (n+1) 次 Bézier 曲线的技术——曲线形状完全不变,但控制点增加了一个。这在 CAD 数据交换中非常有用(例如,将二次曲线导入只支持三次曲线的系统)。n 次升到 n+1 次的公式为:bᵢ^(new) = (i/(n+1)) · bᵢ₅₁^(old) + (1 − i/(n+1)) · bᵢ^(old), i = 0, ..., n+1
0:b₅₁^(old) = bₙ₊₁^(old) = 0。例如,将二次 Bézier(n=2)升阶为三次(n=3):b₀^(new) = b₀
b₁^(new) = (1/3)·b₀ + (2/3)·b₁
b₂^(new) = (2/3)·b₁ + (1/3)·b₂
b₃^(new) = b₂
15.6.2 B 样条
d₀, d₁, ..., dₙ —— 定义曲线的基本形状。U = [u₀, u₁, ..., uₕ] —— 非递减实数序列,定义参数空间的划分。k —— 多项式片的次数(阶数 = k+1)。m = n + k + 1(节点数 = 控制点数 + 次数 + 1)。0次基函数(分段常数):
Nᵢ,₀(u) = { 1, 如果 uᵢ ≤ u < uᵢ₊₁
0, 否则 }
k次基函数(k ≥ 1):
Nᵢ,ᵣ(u) = (u − uᵢ) / (uᵢ₊ᵣ − uᵢ) · Nᵢ,ᵣ⁻¹(u)
+ (uᵢ₊ᵣ₊₁ − u) / (uᵢ₊ᵣ₊₁ − uᵢ₊₁) · Nᵢ₊₁,ᵣ⁻¹(u)
0/0 = 0(处理重节点导致的除零情况)。f(u) = Σᵢ₀ⁿ Nᵢ,ᵣ(u) · dᵢ, u ∈ [uᵣ, uₙ₊₁] (15.12)
u 仅在区间 [uᵣ, uₙ₊₁] 上有效——在该区间内,每个 u 被至少 k+1 个非零基函数覆盖。Nᵢ,₀(u) = 1 当 u ∈ [uᵢ, uᵢ₊₁)
0 否则
Nᵢ,₁(u) = [(u−uᵢ)/(uᵢ₊₁−uᵢ)] · Nᵢ,₀(u) + [(uᵢ₊₂−u)/(uᵢ₊₂−uᵢ₊₁)] · Nᵢ₊₁,₀(u)
15.6.2b 节点向量的三种类型——深度解析
节点重数 r 对 k 次 B 样条连续性的影响 具体示例(k=3,三次) 视觉效果 r = 1(单节点) Cᵏ⁻¹ 连续性 C² —— 曲率连续,无任何折痕 完全丝滑 r = 2(双重节点) Cᵏ⁻² 连续性 C¹ —— 切线连续,曲率可能跳变 无角点,但反射中可能看到折痕 r = 3(三重节点) Cᵏ⁻³ 连续性 C⁰ —— 仅位置连续,产生可见角点 明显的尖锐转角 r = k+1(k+1 重) C⁻¹(不连续) 曲线在该处断开(分段) 两条独立的曲线
类型 定义 示例 (n=7, k=3) 端插值? 均匀 (Uniform) uᵢ₊₁−uᵢ = 常数 [0,1,2,3,4,5,6,7,8,9,10,11] 否——曲线不通过首尾控制点 开放均匀 (Open Uniform) 首尾 k+1 个节点重复,中间等距 [0,0,0,0,1,2,3,4,5,5,5,5] 是——退化到Bézier端点行为 非均匀 (Non-uniform) 任意非递减序列 [0,0,0,0,0.5,2,3,4,5,5,5,5] 取决于首尾节点重数 [0,0,0,0,1,1,1,1] 且 n = k 时,B 样条退化为一整段 Bézier 曲线。
Nᵢ,ᵣ(u) 仅在 [uᵢ, uᵢ₊ᵣ₊₁) 上非零。每个控制点 dᵢ 只影响曲线的 k+1 个节点区间。k+1 个非零控制点的凸包内。这是比 Bézier 更强的局部凸包性质。k 次 B 样条天然具有 Cᵣ⁻¹ 连续性。若节点 uᵢ 的重数为 r,则该处连续性降为 Cᵣ⁻ᵇ。
k=3),节点向量为 [0,1,2,3,4,5,...]。在区间 [u₃, u₄] = [3, 4] 上,四个非零基函数 N₀,₃(u), N₁,₃(u), N₂,₃(u), N₃,₃(u) 可以通过 Cox-de Boor 递推显式算出:在 [3, 4] 上(令 t = u−3 ∈ [0,1]):
N₀,₃(u) = (1−t)³ / 6
N₁,₃(u) = (3t³ − 6t² + 4) / 6
N₂,₃(u) = (−3t³ + 3t² + 3t + 1) / 6
N₃,₃(u) = t³ / 6
[0,1] 上满足单位剖分:N₀,₃+N₁,₃+N₂,₃+N₃,₃ = 1。相应的曲线段是四个控制点的加权和:f(u) = N₀,₃(u)·d₀ + N₁,₃(u)·d₁ + N₂,₃(u)·d₂ + N₃,₃(u)·d₃
[u₄, u₅])则使用 d₁, d₂, d₃, d₄——控制点序列每次滑动一个位置,形成"滑动窗口"式的局部组合。这就是 B 样条局部支撑性的具体体现:每个控制点只参与 k+1=4 段曲线的构造。15.6.3 非均匀 B 样条与 NURBS
f(u) = Σ wᵢ Nᵢ,ᵣ(u) dᵢ / Σ wᵢ Nᵢ,ᵣ(u) (15.13)
wᵢ 是与每个控制点 dᵢ 相关联的权重。权重提供了额外的自由度,使得 NURBS 可以:
控制点: b₀ = (1, 0), b₁ = (1, 1), b₂ = (0, 1)
权重: w₀ = 1, w₁ = √2/2, w₂ = 1
节点向量:U = [0, 0, 0, 0, 1, 1, 1, 1]
θ 的圆弧,中间权重的正确值为 w₁ = cos(θ/2)。当 w₁ = 1 时,NURBS 退化为标准 B 样条(产生抛物线而非圆弧);当 w₁ < 1 时,曲线为椭圆弧;当 w₁ > 1 时,曲线为双曲线弧。这种通过单一权重参数在三种圆锥曲线类型之间连续切换的能力是 NURBS 有理形式的精妙之处。n 次有理 Bézier 曲线定义为:f(t) = Σ wᵢ Bᵢⁿ(t) bᵢ / Σ wᵢ Bᵢⁿ(t), t ∈ [0, 1]
n=2),三个控制点 b₀, b₁, b₂ 及其权重 w₀, w₁, w₂ 可以产生椭圆、抛物线或双曲线弧,取决于中间权重 w₁ 的值。当 w₁ = 1 时退化为标准多项式 Bézier;w₁ < 1 时为椭圆弧;w₁ > 1 时为双曲线弧。这是 NURBS 统一框架在 Bézier 特例上的体现。n 次 Bézier 曲线等价于一条节点向量为 [0,0,...,0, 1,1,...,1](首尾各有 n+1 重节点)的 B 样条,控制点完全相同。k。此时每个非零节点区间上的控制点集构成一段独立的 Bézier 曲线。转换后的控制点数量会增加(因为插入了节点),但几何形状完全不变。k 次 B 样条曲线和一个新的节点值 û(位于某个节点区间 [uᵢ, uᵢ₊₁) 内),Boehm 算法计算新控制点:对于 j = i−k+1, ..., i(受 û 影响的 k 个控制点):
d'ᵣ = (1 − αᵣ) · dᵣ₅₁ + αᵣ · dᵣ
其中 αᵣ = (û − uᵣ) / (uᵣ₊ᵣ − uᵣ)
k 个控制点需要更新(其他控制点保持不变),体现了 B 样条的局部修改优势。新节点向量 U' 在 uᵢ 和 uᵢ₊₁ 之间插入了 û 并保留原节点的顺序。
15.6.4 NURBS 深度解析——工业标准的内在逻辑
P̂ᵢ = (wᵢ·xᵢ, wᵢ·yᵢ, wᵢ·zᵢ, wᵢ) ∈ ℝ⁴
f(u) = (X(u)/w(u), Y(u)/w(u), Z(u)/w(u))
15.7 小结
曲线类型 控制接口 插值/逼近 连续性 局部控制 凸包性质 精确表示圆锥曲线 典型应用 Hermite 端点 + 切线向量 插值端点 Cⁿ(单片) 否 否 否 动画路径 Bézier 控制点 逼近(端点插值) Cⁿ(单片) 否 是 否 矢量字体、曲线造型 自然三次样条 数据点 插值所有点 C²(片间) 否(全局) 否 否 数据拟合、插值 B 样条 控制点 + 节点向量 逼近 Cᵣ⁻¹(天然) 是(k+1段) 是 否 CAD/CAM NURBS 控制点 + 权重 + 节点向量 逼近 Cᵣ⁻¹(天然) 是(k+1段) 是 是 工业标准 (IGES/STEP)
15.9 细分曲线
15.9.1 Chaikin 算法——"角切割"的经典实现
对于控制多边形每条边 (Pᵢ, Pᵢ₊₁),生成两个新点:
Q₂ᵢ = ¾·Pᵢ + ¼·Pᵢ₊₁ (靠左端的 1/4 处)
Q₂ᵢ₊₁ = ¼·Pᵢ + ¾·Pᵢ₊₁ (靠右端的 3/4 处)
15.9.2 Bézier 细分——de Casteljau 的精确剖分
15.9.3 细分 vs 解析求值——对比分析
维度 细分(Subdivision) 解析求值(Analytical) 精度 迭代渐进收敛,精度随迭代次数增长 一次求值即为精确结果(浮点舍入除外) 计算量 随迭代次数线性增长;每步仅需线性插值 求值 O(k²) 用于 de Casteljau/Cox-de Boor;求值更昂贵 数值稳定性 极好——仅涉及加权平均,无条件稳定 高次多项式可能不稳定(系数正负交替) 并行性 所有边可并行切割,GPU 友好 依赖递推结构,难以并行化 适用场景 渲染(自适应细分至像素精度)、曲面雕刻 求交(需要精确参数定位)、分析(曲率计算) 内存需求 每迭代一次控制点数翻倍(Chaikin)或增倍 仅需存储原始控制点 + 临时寄存器 15.10 弧长与速度重参数化
15.10.1 弧长重参数化的完整算法
Δsᵢ = |f(tᵢ₊₁) − f(tᵢ)| (弦长近似弧长)
S₀ = 0
Sᵢ = Σⱼ₌₀ⁱ⁻¹ Δsⱼ (i = 1, ..., N)
α = (s·L − Sᵢ) / (Sᵢ₊₁ − Sᵢ)
û = tᵢ + α · (tᵢ₊₁ − tᵢ)
15.10.2 弧长参数化对动画的至关重要性
15.10.3 在纹理映射中的应用
15.11 曲线拟合
15.11.1 最小二乘曲线拟合——完整推导
r(t) = Σᵢ₌₀ⁿ cᵢ · φᵢ(t)
E = Σⱼ₌₁ᵐ |pⱼ − r(tⱼ)|²
∂E/∂cₖ = Σⱼ 2(pⱼ − Σᵢ cᵢ·φᵢ(tⱼ)) · (−φₖ(tⱼ)) = 0
⇒ Σⱼ Σᵢ cᵢ·φᵢ(tⱼ)·φₖ(tⱼ) = Σⱼ pⱼ·φₖ(tⱼ)
(ΦᵀΦ) · C = Φᵀ · P
15.11.2 参数化选择对拟合质量的巨大影响
策略 定义 效果 均匀参数化 tⱼ = (j−1)/(m−1)(等间距) 数据点间距不均匀时产生严重失真——曲线在数据密集区"震荡过冲",在稀疏区"偷懒不足"。仅在数据近似均匀分布时可用。 弦长参数化 tⱼ = Σₖ₌₁ʲ⁻¹ |pₖ₊₁−pₖ| / L(累积弦长) 考虑了数据点间的物理距离——曲线在数据稀疏区"走得更快"以覆盖更大间距。实践中几乎是默认选择。 向心参数化 tⱼ = Σₖ₌₁ʲ⁻¹ √|pₖ₊₁−pₖ| / L 在弦长基础上取平方根——进一步"收紧"参数化,减少急弯处的过冲。对于弯曲剧烈的数据集效果优于弦长。 15.11.3 过拟合与欠拟合
15.12 插值曲线
15.12.1 Lagrange 插值的致命缺陷——Runge 现象
15.12.2 自然三次样条 vs 夹紧三次样条——边界条件对比
维度 自然端点条件(f''=0) 夹持端点条件(f'指定) 物理类比 样条两端自由——没有被夹子固定 样条两端被夹子以特定角度固定 端点形状 曲线在两端自然地"伸直"趋于直线 曲线从端点以指定方向"射出" 当数据量少时 3 个数据点产生一条直线(自然样条的最小弯曲能量 = 0 → 直线) 3 个数据点可以产生弯曲(夹持方向强制弯曲) 适用场景 数据拟合(不知道端点导数)、科学可视化("最低假设") CAD 设计(需要控制出口方向)、动画路径(进入/离开方向要求) 外推行为 离开端点后继续直线延伸(无害的外推) 离开端点后可能大幅度偏离预期(取决于夹持切线) 15.12.3 插值 vs 逼近——哲学与方法论区别
维度 插值 逼近 核心承诺 曲线精确通过所有数据点 曲线尽量接近数据点,但不保证穿过 对噪声的态度 直接吸收噪声——噪声越大,曲线越怪异 可"忽略"���声——通过选择低阶数拒绝高频噪声 自由度 数据点数 = 多项式次数+1(固定) 基函数数量 < 数据点数(可调) 典型场景 动画关键帧(关键帧必须准确到位)、导航路径(折点必须精确通过) 逆向工程扫描点云(扫描有噪声,不需要精确穿过每个点)、实验数据平滑 可预测性 点间行为不可预测(可能振荡) 点间行为受控制点约束,更可预测 数学工具 Lagrange、Hermite、自然样条 最小二乘法、Bézier、B 样条、加权最小二乘 15.13 曲面扩展
15.13.1 张量积 Bézier 曲面——完整定义
S(u, v) = Σᵢ₌₀ᵐ Σⱼ₌₀ⁿ Bᵢᵐ(u) · Bⱼⁿ(v) · pᵢⱼ
15.13.2 双三次 Bézier 曲面片——16 个控制点
15.13.3 曲面连续性的 G¹ 条件
F 的控制点:pᵢⱼ (i=0,...,m; j=0,...,n)
G 的控制点:qᵢⱼ (i=0,...,m; j=0,...,n)
共享边界:pᵢ,ₙ = qᵢ,₀ 对所有 i=0,...,m
qᵢ,₁ − qᵢ,₀ = α·(pᵢ,ₙ − pᵢ,ₙ₋₁) + β·(pᵢ₊₁,ₙ − pᵢ,ₙ)
15.14 曲线求交与距离
15.14.1 Bézier 裁剪算法(Bézier Clipping)
15.14.2 点-曲线最近距离的迭代算法
D(t) = |f(t) − Q|²
tₖ₊₁ = tₖ − D'(tₖ) / D''(tₖ)
D'(t) = 2(f(t) − Q)·f'(t)
D''(t) = 2(f'(t)·f'(t) + (f(t) − Q)·f''(t))
15.15 曲线在实际中的应用
15.15.1 字体渲染——TrueType vs PostScript 的 Bézier 选择
15.15.2 游戏中的运动曲线——Catmull-Rom vs Bézier
应用场景 推荐曲线 理由 相机路径(过场动画) Catmull-Rom 设计师放置关键点,曲线自动通过——不需要手动调切线。局部性保证修改一个关键点不影响远处的路径段。 角色骨骼动画曲线 Bézier / Hermite 动画师需要精确控制切线(速度曲线)——Hermite 直接暴露切线,Bézier 通过控制点间接控制。缓动效果通过切线长度调节。 车辆/飞行器轨迹 Catmull-Rom + 弧长重参数化 轨迹必须通过所有路点,且速度均匀(弧长 → 匀速物理运动)。 粒子效果路径 Bézier(二次或三次) 粒子通常只有几个控制点(如喷泉从口到顶到落地)。Bézier 的端点插值性质确保粒子路径有明确的起点和终点。 UI 缓动曲线 三次 Bézier CSS 的 cubic-bezier() 函数正是三次 Bézier 曲线——x 轴=时间,y 轴=进度。设计师通过 4 个控制点定义缓动形状。 15.15.3 CAD 中的 NURBS 工作流
本章核心洞察
课后练习题(含答案)
习题 1:Bézier 曲线求值
习题 2:Bézier 曲线与 Hermite 曲线转换
习题 3:曲率计算
习题 4:Cox-de Boor 递推
习题 5:连续性条件
习题 6:Bézier 曲线的凸包性质
习题 7:自然三次样条的端点条件
QA 零基础问答区