3. 自由曲面表示方法
Bezier曲线,说白了就是自由曲面设计的“地基”。我做了这么多年曲面设计,可以负责任地告诉你——如果你搞不懂Bezier,后面NURBS、B样条什么的,学起来会非常痛苦。这一章我们就把Bezier曲线彻底讲透。
3.1 Bezier曲线的定义
Bezier曲线由法国工程师Pierre Bézier在1960年代提出,最初用于汽车车身设计。它的数学定义其实很简洁:
给定n+1个控制点P₀, P₁, ..., Pₙ,n次Bezier曲线定义为:
C(t) = Σᵢ₌₀ⁿ Bᵢₙ(t) · Pᵢ, t ∈ [0, 1]
其中Bᵢₙ(t)是Bernstein基函数:
Bᵢₙ(t) = C(n, i) · tⁱ · (1-t)ⁿ⁻ⁱ
这里C(n, i)是组合数。嗯,公式看着有点抽象,我们来看个具体的例子。
三次Bezier曲线(n=3)是最常用的,有4个控制点:
C(t) = (1-t)³·P₀ + 3t(1-t)²·P₁ + 3t²(1-t)·P₂ + t³·P₃
我个人习惯把控制点想象成“磁铁”——曲线并不穿过中间的控制点,但会被它们“吸引”过去。你想想看,t从0走到1,曲线从P₀出发,逐渐偏向P₁、P₂,最后停在P₃。
核心要点:Bezier曲线始终在控制点构成的凸包内。这个性质在碰撞检测中非常有用——我在做汽车外形设计时,就靠这个快速判断曲面是否与周围部件干涉。
3.2 Bezier曲线的性质
Bezier曲线有5个关键性质,我建议你记牢:
| 性质 | 描述 | 工程意义 |
|---|---|---|
| 端点插值 | 曲线通过P₀和Pₙ | 保证曲线首尾精确连接 |
| 端点切线 | 在P₀处切向P₀→P₁,在Pₙ处切向Pₙ₋₁→Pₙ | 控制曲线进出方向 |
| 凸包性 | 曲线完全在控制点凸包内 | 快速预估曲线范围 |
| 几何不变性 | 仿射变换后仍是Bezier曲线 | 旋转平移不影响曲线形状 |
| 变差缩减性 | 曲线与控制多边形交点不多于控制多边形 | 曲线比控制多边形更“平滑” |
为什么会这样?端点插值是因为t=0时只有B₀ₙ(0)=1,其他基函数全为0;t=1时同理。端点切线性质则来自基函数在端点处的导数特性。
我的经验:做曲面拼接时,端点切线性质是“命根子”。我曾经在汽车A级曲面项目中,就因为没控制好相邻曲线的切线方向,导致曲面接缝处出现肉眼可见的“鼓包”——后来花了整整两天返工。
3.3 de Casteljau算法
de Casteljau算法是计算Bezier曲线上点的最稳定方法。它基于一个简单的几何思想:递归线性插值。
算法步骤(以三次Bezier为例):
- 在四条边上按t比例取点:P₀₁、P₁₂、P₂₃
- 连接新点,再取点:P₀₁₂、P₁₂₃
- 最后连接,取点得到C(t)
代码实现非常直观:
function deCasteljau(points, t) {
// points: 控制点数组,长度 = 次数 + 1
// t: 参数值 [0, 1]
let n = points.length - 1;
let temp = [...points]; // 复制控制点
for (let r = 1; r <= n; r++) {
for (let i = 0; i <= n - r; i++) {
temp[i] = (1 - t) * temp[i] + t * temp[i + 1];
}
}
return temp[0]; // 最终点
}
这个算法的好处是数值稳定性极好。我记得有一次做高精度模具设计,直接用多项式求值会出现抖动,换成de Casteljau算法后,问题立刻解决了。
避坑指南:我曾经在项目中直接用Bernstein基函数求值,结果在t接近0或1时出现数值误差。de Casteljau算法虽然计算量稍大,但数值稳定性好得多——尤其是高次曲线(n≥5)时,千万别偷懒。
3.4 Bezier曲线的拼接
单条Bezier曲线能表示的形状有限。实际工程中,我们通常把多条Bezier曲线首尾相连——这就是拼接。
C⁰连续(位置连续):前一条曲线的终点等于后一条曲线的起点。
Pₙ = Q₀
C¹连续(切线连续):在C⁰连续的基础上,切线方向一致且长度成比例。
Pₙ - Pₙ₋₁ = k · (Q₁ - Q₀), k > 0
当k=1时,称为G¹连续(几何连续),只要求方向相同,不要求长度相等。
C²连续(曲率连续):在C¹连续的基础上,二阶导数也连续。这个要求更严格:
Pₙ₋₂, Pₙ₋₁, Pₙ(=Q₀), Q₁, Q₂ 五点共面且满足特定比例关系
我做个对比表格,方便你理解:
| 连续类型 | 条件 | 视觉效果 | 工程应用 |
|---|---|---|---|
| C⁰ | 位置相同 | 有折角 | 简单轮廓 |
| C¹ / G¹ | 切线方向一致 | 光滑无折角 | 一般工业曲面 |
| C² | 曲率连续 | 高光连续 | 汽车A级曲面 |
工程真相:汽车外覆盖件要求至少G²连续,否则喷漆后会出现“橘皮”或“波浪”。我参与过的一个项目,就因为拼接处只做到了G¹,样车出来后高光线一照,接缝处明显“断光”——最后全部返工重做。
3.5 知识体系总览
下面这张图把本章的核心逻辑串起来了:
3.6 工程实践建议
最后,我总结几条实战经验:
- 控制点数量:单条Bezier曲线不要超过7个控制点(6次),否则容易出现数值振荡。需要复杂形状时,用多条低次曲线拼接。
- 参数范围:t始终在[0,1]区间。如果遇到需要分段参数的情况,考虑用B样条代替。
- 连续性检查:拼接后一定要用曲率梳(Curvature Comb)检查——肉眼看不出的问题,曲率梳一照就现原形。
- 数值稳定性:高精度计算时,优先用de Casteljau算法而不是直接展开多项式。
我的习惯:每次做完曲线拼接,我都会在接缝处取5-10个点,手动计算切线方向和曲率值。虽然工具能自动检查,但亲手算一遍能发现很多工具发现不了的细节问题。
Bezier曲线是自由曲面设计的起点。把这一章吃透,后面学B样条和NURBS会轻松很多。记住:控制点就是你的“画笔”,连续性条件就是你的“标尺”——两者配合好,才能画出漂亮的曲面。