計算機圖形學:貝塞爾曲線和B樣條

貝塞爾曲線和B樣條

1.Bézier curve貝塞爾曲線

一個連續函數都可以用一個多項式無限逼近

貝塞爾曲線於 1962 年,由法國工程師皮埃爾·貝濟埃(Pierre Bézier)所廣泛發表,他運用貝塞爾曲線來爲汽車的主體進行設計。

1.1 一階貝塞爾曲線

image

B1(t)=(1t)P0+tP1,t[0,1] \mathbf{B_1(t)= (1-t)P_0 + tP_1, t\in[0, 1]}

1.2 二階貝塞爾曲線

image

P0=(1t)P0+tP1 P1=(1t)P1+tP2 B2(t)=(1t)P0+tP1=(1t)2P0+2t(1t)P1+t2P2 \mathbf{P_0'= (1-t)P_0 + tP_1} \\ \ \\ \mathbf{P_1'= (1-t)P_1 + tP_2} \\ \ \\ \mathbf{B_2(t)= (1-t)P_0' + tP_1'=(1-t)^2P_0+2t(1-t)P_1+t^2P_2} \\

1.3 三階貝塞爾曲線

image

B3(t)=(1t)3P0+3t(1t)2P1+3t2(1t)2P1+t3P3 \mathbf{B_3(t)= (1-t)^3P_0 + 3t(1-t)^2P_1 + 3t^2(1-t)^2P_1 + t^3P_3}

1.4 多階貝塞爾曲線

Bernstein polynomial(伯恩斯坦多項式)

Bn(t)=i=0nCniPi(1t)niti=i=0nBi,nPi Cni=n!(ni)!i! Bi,n=n!(ni)!i!(1t)niti \mathbf{B_n(t)= \sum_{i=0}^{n} C_{n}^{i} P_i (1-t)^{n-i}t^i = \sum_{i=0}^{n} B_{i,n} P_i } \\ \ \\ \mathbf{C_{n}^{i} = \frac{n!}{(n-i)!\cdot i!}}\\ \ \\ \mathbf{B_{i,n} = \frac{n!}{(n-i)!\cdot i!}(1 - t)^{n-i}t^i}\\

1.5 de Casteljau

在這裏插入圖片描述

Pi,j\bm{P_{i,j}}表示第i列的第j個點
Pi,j=(1t)Pi1,j+tPi1,j+1 i[1,n],j[1,ni+1] \mathbf{P_{i, j} = (1 - t)P_{i - 1, j} + tP_{i - 1, j + 1}}\\ \ \\ \mathbf{i \in [1, n], j \in [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=0nBi,nPi \mathbf{B_n(t)= \sum_{i=0}^{n} B_{i,n} P_i }
則:
Bn(t)=i=0nBi,nPi=i=0n(1t+t)Bi,nPi \mathbf{B_n(t)= \sum_{i=0}^{n} B_{i,n} P_i = \sum_{i=0}^{n} (1-t + t) B_{i,n} P_i}

接下來看下相乘的兩個式子

式子1:

(1t)Bi,nPi=n!(ni)!i!(1t)n+1itiPi =n+1in+1(n+1)!(n+1i)!i!(1t)n+1itiPi=n+1in+1Bi,n+1Pi (1t)Bi,nPi=n+1in+1Bi,n+1Pi \mathbf{(1 - t)B_{i, n}P_i = \frac{n!}{(n-i)!\cdot i!}(1 - t)^{n + 1 - i}t^i P_i }\\ \ \\ \mathbf{= \frac{n + 1 - i}{n + 1}\frac{(n+1)!}{(n + 1 - i)!\cdot i!}(1 - t)^{n + 1 - i}t^i P_i = \frac{n + 1 - i}{n + 1}B_{i, n + 1}P_i}\\ \ \\ \mathbf{(1 - t)B_{i, n} P_i = \frac{n + 1 - i}{n + 1}B_{i, n + 1}P_i }\\

式子2:

tBi,nPi=n!(ni)!i!(1t)niti+1Pi =i+1n+1(n+1)!(n+1i1)!(i+1)!(1t)n+1i1ti+1Pi=i+1n+1Bi+1,n+1Pi tBi,nPi=i+1n+1Bi+1,n+1Pi \mathbf{tB_{i, n}P_i = \frac{n!}{(n-i)!\cdot i!}(1 - t)^{n - i}t^{i + 1} P_i }\\ \ \\ \mathbf{= \frac{i + 1}{n + 1}\frac{(n+1)!}{(n + 1 - i - 1)!\cdot (i + 1)!}(1 - t)^{n + 1 - i - 1}t^{i + 1} P_i = \frac{i + 1}{n + 1}B_{i + 1, n + 1}P_i}\\ \ \\ \mathbf{tB_{i, n}P_i = \frac{i + 1}{n + 1}B_{i + 1, n + 1}P_i}\\

對於等式1,由於i = n + 1的時候等式爲0,所以可以將等式變爲

i=0nn+1in+1Bi,n+1Pi=i=0n+1n+1in+1Bi,n+1Pi \mathbf{\sum_{i = 0}^{n}\frac{n + 1 - i}{n + 1}B_{i, n + 1}P_i = \sum_{i = 0}^{n + 1}\frac{n + 1 - i}{n + 1}B_{i, n + 1}P_i}

對於等式2我們可以將i用i-1替代,因爲i=-1時等式爲0,所以成立,所以

i=0ni+1n+1Bi+1,n+1Pi=i=0n+1in+1Bi,n+1Pi1 \mathbf{\sum_{i = 0}^{n}\frac{i + 1}{n + 1}B_{i + 1, n + 1}P_i = \sum_{i = 0}^{n + 1}\frac{i}{n + 1}B_{i, n + 1}P_{i - 1}}

將兩式子合併最終結果爲:

Bn(t)=i=0nBi,nPi=i=0n+1(n+1in+1Pi+in+1Pi1)Bi,n+1 \mathbf{B_n(t)= \sum_{i=0}^{n} B_{i,n} P_i = \sum_{i = 0}^{n + 1}(\frac{n + 1 - i}{n + 1}P_i + \frac{i}{n + 1}P_{i - 1}) B_{i, n + 1}}

其中P1,Pn+1\bm{P_{-1}},\bm{P_{n + 1}}值隨意,畢竟最後乘以係數後均爲0

新的節點推導公式爲:
Pi=(n+1in+1Pi+in+1Pi1) \mathbf{P_i^* = (\frac{n + 1 - i}{n + 1}P_i + \frac{i}{n + 1}P_{i - 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=(ninPi+inPi1) \mathbf{P_i^* = (\frac{n - i}{n}P_i + \frac{i}{n}P_{i - 1})}

可以得到如下兩個遞推式

Pi=nPiiPi1nii=0,1,2...n1 Pi1=nPi(ni)Piii=n,n1,...1 \mathbf{P_i' = \frac{nP_i^* - iP_{i - 1}'}{n - i} \qquad i = 0, 1, 2...n-1}\\ \ \\ \mathbf{P_{i - 1}'' = \frac{nP_i^* - (n - i)P_{i}''}{i} \qquad i=n, n-1,...1}\\

一個與起點重合,然後逐漸偏離;一個與終點重合,然後逐漸偏離

Then we have two kinds of degree reduction schemes

1.7.1 Forrest (1972)

Pi^={Pi,i=0,1,...,[n12]Pi,i=[n12]+1,...n1 \mathbf{\hat{P_i} = \left\{\begin{matrix} P_i' , & i = 0,1,..., \left [ \frac{n - 1}{2} \right ] \\ P_i'', & i = \left[\frac{n - 1}{2} \right ] + 1,...n - 1 \end{matrix}\right.}

1.7.2 Farin (1983)

Pi^=(1in1)Pi+in1Pi \mathbf{\hat{P_i} = (1 - \frac{i}{n - 1})P_i' + \frac{i}{n - 1}P_i''}


2 B-Spline

Pn(t)=i=0nPiNi,k(t) t[0,1] P_n(t) = \sum_{i=0}^{n}P_iN_{i, k}(t)\\ \ \\ t \in [0, 1]\\

2.1 樣條

樣條(Spline)其實是一種在造船和工程製圖時用來畫出光滑形狀的工具。樣條是一根柔軟但有彈性的長條物,有些像尺子。將兩端和幾個點用釘子固定之後,便可以產生順滑的曲線。

image

2.2 Cox-de Boor recursion formula

Ni,1={1ti<x<ti+10otherwise Ni,k=ttiti+k1tiNi,k1(t)+ti+ktti+kti+1Ni+1,k1(t) \mathbf{N_{i,1} = \left\{\begin{matrix} 1 & t_i < x < t_{i + 1}\\ 0 & otherwise \end{matrix}\right.}\\ \ \\ \mathbf{N_{i,k} = \frac{t - t_i}{t_{i+k-1} - t_i}N_{i, k-1}(t) + \frac{t_{i+k} - t}{t_{i+k} - t_{i+1}}N_{i+1, k-1}(t)}\\

我們讓t0=0,t1=1,t2=2,t3=3t_0 = 0,t_1 = 1,t_2 = 2, t_3 = 3,則N0,1,N1,1,N2,1N_{0, 1}, N_{1, 1}, N_{2, 1}如下圖所示:

在這裏插入圖片描述

遞推關係如下(此圖爲wiki上的,用的是次-degree,而上面的公式用的是階-order,degree=order-1):

image

2.2.1 定義區間

[tk1,tn+1][t_{k-1},t_{n+1}]區間內有相應數量的基函數,該區間纔有意義:

image

2.3 分類

2.3.1 均勻B樣條(Uniform B-Spline)

節點成等差數列均勻分佈

image

2.3.2 準均勻B樣條(Quasi-Uniform B-Spline)

讓起點和終點都具有K的重複度,使得曲線從起點開始,到終點結束

image

2.3.3 分段Bezier曲線(Piecewise Bezier Curve)

  • 起點節點和終點節點都具有K的重複度
  • 所有其它節點都具有K-1的重複度
  • 這樣所有的曲線段都是Bezier曲線,各自獨立

image

2.3.4 非均勻B樣條(Non-uniform B-Spline)

  • 起始點重複度都≤K
  • 其它節點重複度≤K-1

De Boor’s Algorithm

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章