天天看點

Unraveling Bezier Splines

Unraveling Beziér Splines

by Justin Reynen

原文網址:http://www.gamedev.net/reference/articles/article888.asp

簡介

毫無疑問,您已經聽說過這些用于處理曲線和曲面的新技術,二次Bezier曲線,三次Bezier曲線,非均勻有理B樣條(NURBS),并且非常迫切的想要把所有這些東西搞清楚,甚至可能嘗試将這些技術中的一種加入到您正在制作的遊戲或示範中。

這篇文章是幫您揭開這些謎團的最好的開始。

在本文中,我會向你解釋Bezier曲線的數學原理,編寫程式畫出一條二次Bezier樣條(最簡單的樣條),然後你就可以自己實作任意你所需要次數的Bezier曲線了。

Bezier曲線的數學原理

好了,我們将要作的第一件事是溫習一下Bernsteins基本方程。在下面我會給出一個公式,别着急,你看,她很簡單!

1 = t + (1 - t)

T為任意值等式都成立,但是我們所關注的T值是在0和1之間。

好,現在我們已經了解Bernsteins基本方程了,下面将要開始生成曲線的工作。我們選擇二次Bezier曲線作為切入點,因為它是最容易實作的。。

好了,現在已經确定我們想要一條二次Bezier曲線,我們需要從萬能的基本方程派生出我們需要的方程,現在就開始吧!

對于二次Bezier曲線,我們需要将Bernsteins基本方程的兩段同時取平方;對于三次Bezier曲線,我們就去立方,以此類推。下面是兩邊取平方後的Bernsteins基本方程

1^2 = (t + (1 - t))^2

1 = t^2 + 2*t*(1-t) + (1-t)*(1-t)

可能你注意到有很多項我沒有展開,因為這樣更有助于了解和編碼。

好的,現在我們獲得了從基本方程衍生出來的3個函數。你可能會問他們在哪兒,就在你的面前!我們的函數就是等式右側的那3個多項式。我們将這3個函數取名為Bx(t)。

#define B1(t) (t*t)

#define B2(t) (2*t*(1-t))

#define B3(t) ((1-t)*(1-t))

你應該注意到,對于二次Bezier曲線有三個函數,對于三次Bezier曲線有四個參數,以此類推。在本文的示範程式中我已經計算了三次和四次曲線的方程,請檢視"Functions.txt"

好了,現在我們已經搞清楚Bezier曲線的簡單數學意義,接下來讓我們談一下編碼吧。

編碼實作Bezier曲線

好的,我們已經準備好了基本函數,現在是充分利用他們的時候了。

我認為現在你應該意識到與這3個函數相對應,有3個控制點,我們将這些點起名叫Cx。你可以向這樣來存儲這些點:

typedef struct sCPoint

{

int x;

int y;

} C_POINT;

注:我們将要生成的是2DBezier曲線,如果你想要生成3DBezier曲線的話可以在結構中加入一個z元素。

C_POINT controlP[3];

好了,現在我們将要接觸在螢幕上繪制Bezier曲線的真正代碼了。目前,我們的曲線隻存在于想象之中,而且我們隻有數學方程。我們需要做的就是利用數學方程,沿着曲線将點畫在螢幕上。

這就給我們帶來了最後一個問題“采樣率”。采樣率就是我們在曲線上畫點時,每繪制一個點需要沿着曲線移動的距離。采樣率是個小數,你可以簡單的把它了解為百分比。例如采樣率0.5的含義就是:從曲線的一端開始,在這裡繪制一個點;然後沿曲線移動50%,然後繪制一個點,然後再移動50%(到達曲線的末端),繪制最後一個點。這樣就會在曲線的左端、中間和右端共繪制了3個點。我們需要一個計數器來記錄已經繪制的曲線的百分比,然後我們每次對計數器累加,直到計數器到達1為止。定制的采樣率越小,我們繪制的點就越多,曲線看起來就越精細。

//Note: it is assumed that each controlP has already been filled out with

//an x and y coordinate.

double count; //used as our counter

double detailBias; //how many points should we put on our curve.

double x,y; //used as accumulators to make our code easier to read

detailBias = 1 / 50; //we'll put 51 points on out curve (0.02 detail bias)

do

{

x = controlP[0].x*B1(count) + controlP[1].x*B2(count) + controlP.x[2]*B2(count);

y = controlP[0]*B1.y(count) + controlP[1].y*B2(count) + controlP.y[2]*B2(count);

PutPixel(x,y,RGB(255,255,255));

count += detailBias;

}while( count <= 1);

請注意我們是如何獲得x和y的值。我們用控制點與相應的基本方程相乘,然後将他們加在一起。我們對x和y坐标進行了這樣的操作,如果我們是工作在3維空間,那麼我們也要對z坐标進行一樣的運算。

用Bezier曲線建立曲面

我現在就要揭開如何繪制Bezier曲面的神秘面紗。這是個很大的課題,完全可以把它單獨拿出來寫一篇文章,而且它也超出了本文的研究範疇。我将隻介紹二次Bezier曲面,并且沒有提供示範代碼。我将會介紹如何生成曲面上的點,你可以很容易的将其改造成3次或者4次曲面。

<shapetype id="_x0000_t75" stroked="f" filled="f" path="[email protected]@[email protected]@[email protected]@[email protected]@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 208.5pt; HEIGHT: 126.75pt" alt="" type="#_x0000_t75"><imagedata o:href="http://www.gamedev.net/reference/programming/features/unrav_bezier/curves.gif" target="_blank" rel="external nofollow" src="file:///C:%5CDOCUME~1%5CSUNFEN~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.gif"></imagedata></shape>

上面這幅圖是最基本的內插補點曲面,它由2次Bezier曲線組成。它有9個控制點,你可以想象這幅圖的x軸沿7、8、9方向,y軸沿7、4、1方向。為了讓事情簡單,我把采樣率定為0.25,這樣我們在每條線上都會産生5個點。在整個面上将會生成25個點。我們可以簡單的把這些點以行和列分組,這樣我們的資料結構就會像這樣:

C_POINT points[5][5];

我們要做的工作就是對每一條曲線進行插值,産生新的控制點,然後再由新生成的控制點繼續插值,這樣就生成了我們需要的曲面。

In Conclusion

我希望這篇文章可以幫助你了解Bezier曲線的用法并且能夠将他們應用到你的遊戲或者示範當中。在本文結束之前,提出一些關于Bezier曲線的優點和缺點:

Pro's:

在層次細節模型當中,曲面是一個非常好的用于減少繪制多邊形數量的工具。你可以很容易的将這些面減少到隻有4個多邊形(對于2次方程),而且你可以很容易的做到這一點(通過改變采樣率)。它也可以很容易的使表面變得平滑。另外,如果你計劃添加錄影機移動功能的話,Bezier曲線對于生成平滑的移動路線,動畫移動來說是至關重要的。

Con's:

曲面對于大多數引擎來說最主要的缺點就是要花費太長的時間将曲面變成多邊形,你在載入時做這些事情也不會有太大改變。但是如果你每一幀都進行計算的話,你可能會注意到它存在巨大的性能問題。這就是大多數引擎開發者對曲面發牢騷的最主要原因。

(happykevins譯)

繼續閱讀