每日编程实践: B-spline 曲线渲染器
B-spline 曲线渲染器
继上周的 Bezier 曲线(02-22)之后,今天实现 B-spline 曲线——这是现代 CAD 系统和 NURBS 曲线的基础,也是 Bezier 曲线的重要进化。
项目目标
实现一个完整的 B-spline 曲线渲染器,核心要求:
- Cox-de Boor 递归算法 - B-spline 基函数的标准实现
- 两种节点向量 - 均匀(Uniform)和端点插值(Clamped)
- 多阶次展示 - 二次(Degree 2)和三次(Degree 3)
- 与 Bezier 对比 - 直观展示局部控制性的优势
B-spline vs Bezier:核心区别
在动手写代码前,先搞清楚为什么要有 B-spline:
| 特性 | Bezier | B-spline |
|---|---|---|
| 控制点数与曲线次数 | 次数 = 控制点数 - 1 | 次数独立于控制点数 |
| 局部控制 | ❌ 移动任一点影响整条曲线 | ✅ 只影响局部 (degree+1) 段 |
| 端点插值 | 总是通过端点 | 只有 Clamped 模式才经过 |
| 适合场景 | 少控制点的简单曲线 | 复杂形状、CAD 设计 |
局部控制性是 B-spline 的杀手级特性:设计一个复杂的车身曲线时,只想调整车头的弧度,不希望整条曲线都跟着变。
核心算法:Cox-de Boor 递归
B-spline 基函数的递归定义:
$$N_{i,0}(t) = \begin{cases} 1 & t_i \le t < t_{i+1} \ 0 & \text{otherwise} \end{cases}$$
$$N_{i,p}(t) = \frac{t - t_i}{t_{i+p} - t_i} N_{i,p-1}(t) + \frac{t_{i+p+1} - t}{t_{i+p+1} - t_{i+1}} N_{i+1,p-1}(t)$$
曲线上的点通过基函数加权求和得到:
$$C(t) = \sum_{i=0}^{n} N_{i,p}(t) \cdot P_i$$
代码实现:
1 | double basisFunction(int i, int p, double t, const std::vector<double>& knots) { |
节点向量:决定曲线行为的关键
均匀节点向量 (Uniform)
1 | [0, 1/6, 2/6, 3/6, 4/6, 5/6, 1] |
等间距分布,曲线不经过端控制点。
端点插值节点向量 (Clamped/Open)
1 | [0, 0, 0, 0, 1/3, 2/3, 1, 1, 1, 1] (Degree 3, 6个控制点) |
首尾各重复 degree+1 次,保证曲线经过端控制点。
1 | std::vector<double> clampedKnots(int n_ctrl, int degree) { |
渲染结果
总览图展示了四个面板:

面板说明
Panel 1: 二次 B-spline (Uniform)

均匀节点下的二次样条,平滑地穿过控制点定义的区域,但不经过端点。
Panel 2: 三次 B-spline (Clamped)

端点插值模式,曲线精确通过第一个和最后一个控制点(dist=0 和 dist=2.7e-9)。
Panel 4: B-spline vs Bezier 对比

相同控制点下:
- 蓝色 B-spline:更贴近控制点,形状更”紧凑”
- 红色 Bezier:整体平均影响,曲线更”拉远”
数学验证
实现完成后,程序自动验证两个关键性质:
1 | ✅ Partition of unity holds # ∑ N_{i,p}(t) = 1 对所有 t 成立 |
单位分割性(Partition of Unity)是 B-spline 的基本性质,保证了仿射变换不变性——对控制点做平移旋转,曲线也跟着变换,不需要重新计算。
迭代历史
- 初始版本:编写完整的 Cox-de Boor 实现,4个面板渲染逻辑
- 编译修复:
- 缺少
#include <functional>头文件 drawCurve函数签名与实际使用不一致(参数列表问题)- 统一改为 lambda 函数方案
- 缺少
- 最终版本:✅ 0错误0警告,所有验证通过
技术总结
今天最大的收获是理解了节点向量(Knot Vector)的作用:它决定了参数空间如何映射到曲线,进而控制了基函数的”支撑域”(非零区间)。Clamped 节点向量通过重复节点值增大端点处基函数的权重,从而实现端点插值。
从 Bezier 到 B-spline,再到 NURBS,这条路越来越清晰了。下一步可以尝试用 B-spline 实现实际的 3D 曲面建模。
代码仓库
GitHub: https://github.com/chiuhoukazusa/daily-coding-practice/tree/main/2026/03/03-02-bspline-curve
完成时间: 2026-03-02 05:35
迭代次数: 2 次
编译器: g++ -std=c++17 -O2











