B样条
B样条曲线(B-spline curves)是一种基于样条函数(spline function)的分段多项式函数,广泛用于计算机图形学、数据拟合和数值分析中。B样条曲线有许多优点,如局部控制、平滑性和灵活性。
1. 基本概念
1.1 节点向量( Knot Vector )
节点向量是一个非递减序列 {ti}\{t_i\}{ti},其中iii从 000到 n+k+1n+k+1n+k+1,nnn是控制点的数量,kkk是B样条曲线的阶数(degree)。节点向量决定了B样条基函数的定义域。
1.2 B样条基函数(Basis Functions)
B样条基函数 Bi,k(t)B_{i,k}(t)Bi,k(t) 是分段多项式函数,它是定义B样条曲线的重要组成部分。基函数的定义是递归的:
- 零阶基函数(piecewise constant):Bi,0(t)={1ti≤t<ti+10otherwiseB_{i,0}(t) = \begin{cases} 1 & t_i \leq t < t_{i+1} \\ 0 & \text{otherwise} \end{cases}Bi,0(t)={10ti≤t<ti+1otherwise
- 递归定义高阶基函数:Bi,k(t)=t−titi+k−1−tiBi,k−1(t)+ti+k−tti+k−ti+1Bi+1,k−1(t)B_{i,k}(t) = \frac{t - t_i}{t_{i+k-1} - t_i} B_{i,k-1}(t) + \frac{t_{i+k} - t}{t_{i+k} - t_{i+1}} B_{i+1,k-1}(t)Bi,k(t)=ti+k−1−tit−tiBi,k−1(t)+ti+k−ti+1ti+k−tBi+1,k−1(t)
float B(int i, int k, float t, const std::vector<float>& knots) {
if (k == 1) {
return (knots[i] <= t && t < knots[i+1]) ? 1.0f : 0.0f;
} else {
float coeff1 = (t - knots[i]) / (knots[i + k - 1] - knots[i]);
float coeff2 = (knots[i + k] - t) / (knots[i + k] - knots[i + 1]);
return coeff1 * B(i, k - 1, t, knots) + coeff2 * B(i + 1, k - 1, t, knots);
}
}
2. B样条曲线的数学表达式
给定一个控制点序列 {Pi}\{P_i\}{Pi} 和一个节点向量 {ti}\{t_i\}{ti},B样条曲线 P(t)P(t)P(t) 的表达式为:
P(t)=∑i=0nPiBi,k(t) t∈[tk−1,tn+1]P(t)=\sum_{i=0}^{n}P_iB_{i,k}(t) \ \ \ \ t\in[t_{k-1},t_{n+1}]P(t)=∑i=0nPiBi,k(t) t∈[tk−1,tn+1]
其中:
● PiP_iPi是第iii个控制点
● Bi,k(t)B_{i,k}(t)Bi,k(t)是阶数为kkk的第iii个B样条基函数
3. B样条的类型
- 均匀B样条曲线:当节点沿参数轴均匀等距分布,即uuui+1-uuui=常数>0时,表示均匀B样条函数。
- 准均匀B样条曲线:与均匀B样条曲线的差别在于两端节点具有重复度k,这样的节点矢量定义了准均匀的B样条基。
- 分段Bezier曲线:节点矢量中两端节点具有重复度k,所有内节点重复度尾k-1,这样的节点矢量定义了分段的Bernestein基。B样条曲线用分段Bezier曲线表示后,各曲线段就具有了相对独立性。
- 非均匀B样条曲线:当节点沿参数轴的分布不等距,即uuui+1-uuui≠\neq=常数时,表示非均匀B样条函数
4. 绘制代码
void BSplineCurve::calculateKnots()
{
// 均匀B样条
// 控制点个数 n+1
// 阶数k
int n = controlPoints.size() - 1;
int k = degree;
int m = n + k + 1;
knots.resize(m + 1);
// 有m+1个矢量结点
for (int i = 0; i <= m; ++i)
{
knots[i] = float(i) / (m - degree + 1);
}
}
float BSplineCurve::B(int i, int k, float t)
{
if (k == 1)
return (knots[i] <= t && t < knots[i + 1]) ? 1.0f : 0.0f;
else
{
float coeff1 = (t - knots[i]) / (knots[i + k - 1] - knots[i]);
float coeff2 = (knots[i + k] - t) / (knots[i + k] - knots[i + 1]);
return coeff1 * B(i, k - 1, t) + coeff2 * B(i + 1, k - 1, t);
}
}
void BSplineCurve::calculateBSplinePoints()
{
int n = controlPoints.size() - 1;
vertices.clear();
for (int j = 0; j <= 64; ++j)
{
float t = (float)j / 64.0f * (knots[n + 1] - knots[degree]) + knots[degree];
Vertex v;
for (int i = 0; i <= n; ++i)
{
float basis = B(i, degree + 1, t);
v.position += basis * controlPoints[i];
}
vertices.push_back(v);
}
}
2970

被折叠的 条评论
为什么被折叠?



