貝塞爾曲線和B樣條
1.Bézier curve貝塞爾曲線
一個連續函數都可以用一個多項式無限逼近
貝塞爾曲線於 1962 年,由法國工程師皮埃爾·貝濟埃(Pierre Bézier)所廣泛發表,他運用貝塞爾曲線來爲汽車的主體進行設計。
1.1 一階貝塞爾曲線
B1(t)=(1−t)P0+tP1,t∈[0,1]
1.2 二階貝塞爾曲線
P0′=(1−t)P0+tP1 P1′=(1−t)P1+tP2 B2(t)=(1−t)P0′+tP1′=(1−t)2P0+2t(1−t)P1+t2P2
1.3 三階貝塞爾曲線
B3(t)=(1−t)3P0+3t(1−t)2P1+3t2(1−t)2P1+t3P3
1.4 多階貝塞爾曲線
Bernstein polynomial(伯恩斯坦多項式)
Bn(t)=i=0∑nCniPi(1−t)n−iti=i=0∑nBi,nPi Cni=(n−i)!⋅i!n! Bi,n=(n−i)!⋅i!n!(1−t)n−iti
1.5 de Casteljau
Pi,j表示第i列的第j個點
Pi,j=(1−t)Pi−1,j+tPi−1,j+1 i∈[1,n],j∈[1,n−i+1]
de Casteljau算法在Bézier曲線的光柵化階段特別有用。
Vector2 Render::CalculateBezierPoint(const std::vector<Vector2>& ctl_vecs, float t){
std::vector<Vector2> points(ctl_vecs);
for (int i = 0; i < points.size() - 1; ++i) {
for (int j = 0; j < points.size() - i - 1; ++j) {
points[j] = interp(points[j], points[j + 1], t);
}
}
return points[0];
}
1.6 升階
增加控制點卻不改變原先曲線的表現
Degree raising means that adding control points to raise the degree of the Bézier curves, but the shape and direction of the curve remain unchanged.
推導過程:
已知:
Bn(t)=i=0∑nBi,nPi
則:
Bn(t)=i=0∑nBi,nPi=i=0∑n(1−t+t)Bi,nPi
接下來看下相乘的兩個式子
式子1:
(1−t)Bi,nPi=(n−i)!⋅i!n!(1−t)n+1−itiPi =n+1n+1−i(n+1−i)!⋅i!(n+1)!(1−t)n+1−itiPi=n+1n+1−iBi,n+1Pi (1−t)Bi,nPi=n+1n+1−iBi,n+1Pi
式子2:
tBi,nPi=(n−i)!⋅i!n!(1−t)n−iti+1Pi =n+1i+1(n+1−i−1)!⋅(i+1)!(n+1)!(1−t)n+1−i−1ti+1Pi=n+1i+1Bi+1,n+1Pi tBi,nPi=n+1i+1Bi+1,n+1Pi
對於等式1,由於i = n + 1的時候等式爲0,所以可以將等式變爲
i=0∑nn+1n+1−iBi,n+1Pi=i=0∑n+1n+1n+1−iBi,n+1Pi
對於等式2我們可以將i用i-1替代,因爲i=-1時等式爲0,所以成立,所以
i=0∑nn+1i+1Bi+1,n+1Pi=i=0∑n+1n+1iBi,n+1Pi−1
將兩式子合併最終結果爲:
Bn(t)=i=0∑nBi,nPi=i=0∑n+1(n+1n+1−iPi+n+1iPi−1)Bi,n+1
其中P−1,Pn+1值隨意,畢竟最後乘以係數後均爲0
新的節點推導公式爲:
Pi∗=(n+1n+1−iPi+n+1iPi−1)
CODE:
std::vector<Vector2> Render::RaiseDegree(const std::vector<Vector2>& ctl_vecs){
unsigned long new_degree = ctl_vecs.size();
std::vector<Vector2> new_ctl_vecs(new_degree + 1);
new_ctl_vecs[0] = ctl_vecs[0];
new_ctl_vecs[new_degree] = ctl_vecs[new_degree - 1];
for (int i = 1; i < new_degree; ++i) {
float t = 1.0 - static_cast<float>(i) / new_degree;
new_ctl_vecs[i] = interp(ctl_vecs[i - 1], ctl_vecs[i], t);
}
return new_ctl_vecs;
}
1.7 降階
減少控制點去逼近原先曲線的表現
Degree reduction is the opposite of degree raising, is to find a curve defined by new control points with minimum error
根據升階公式
Pi∗=(nn−iPi+niPi−1)
可以得到如下兩個遞推式
Pi′=n−inPi∗−iPi−1′i=0,1,2...n−1 Pi−1′′=inPi∗−(n−i)Pi′′i=n,n−1,...1
一個與起點重合,然後逐漸偏離;一個與終點重合,然後逐漸偏離
Then we have two kinds of degree reduction schemes
1.7.1 Forrest (1972)
Pi^={Pi′,Pi′′,i=0,1,...,[2n−1]i=[2n−1]+1,...n−1
1.7.2 Farin (1983)
Pi^=(1−n−1i)Pi′+n−1iPi′′
2 B-Spline
Pn(t)=i=0∑nPiNi,k(t) t∈[0,1]
2.1 樣條
樣條(Spline)其實是一種在造船和工程製圖時用來畫出光滑形狀的工具。樣條是一根柔軟但有彈性的長條物,有些像尺子。將兩端和幾個點用釘子固定之後,便可以產生順滑的曲線。
2.2 Cox-de Boor recursion formula
Ni,1={10ti<x<ti+1otherwise Ni,k=ti+k−1−tit−tiNi,k−1(t)+ti+k−ti+1ti+k−tNi+1,k−1(t)
我們讓t0=0,t1=1,t2=2,t3=3,則N0,1,N1,1,N2,1如下圖所示:
遞推關係如下(此圖爲wiki上的,用的是次-degree,而上面的公式用的是階-order,degree=order-1):
2.2.1 定義區間
[tk−1,tn+1]區間內有相應數量的基函數,該區間纔有意義:
2.3 分類
2.3.1 均勻B樣條(Uniform B-Spline)
節點成等差數列均勻分佈
2.3.2 準均勻B樣條(Quasi-Uniform B-Spline)
讓起點和終點都具有K的重複度,使得曲線從起點開始,到終點結束
2.3.3 分段Bezier曲線(Piecewise Bezier Curve)
- 起點節點和終點節點都具有K的重複度
- 所有其它節點都具有K-1的重複度
- 這樣所有的曲線段都是Bezier曲線,各自獨立
2.3.4 非均勻B樣條(Non-uniform B-Spline)