您好,登錄后才能下訂單哦!
這篇文章主要講解了OpenGL如何繪制Bezier曲線,內(nèi)容清晰明了,對此有興趣的小伙伴可以學(xué)習(xí)一下,相信大家閱讀完之后會有幫助。
項目要求:
– 使用鼠標(biāo)在屏幕中任意設(shè)置控制點,并生成曲線
– 使用鼠標(biāo)和鍵盤的交互操作實現(xiàn)對曲線的修改。
項目總體介紹
本項目利用Bezier曲線生成算法生成可由用戶自定義的曲線??蓪崿F(xiàn)核心功能如下:
1、用戶用鼠標(biāo)左擊屏幕任意處產(chǎn)生記錄點。
2、鼠標(biāo)右擊屏幕任意處由先前的任意個數(shù)記錄點和其先后關(guān)系生成Bezier曲線。
另有輔助輸入功能:
1、按鍵盤‘C'鍵可清除所有記錄點。
2、按鍵盤‘R'鍵可清除上一個記錄點。
3、按鍵盤‘Q'鍵可推出程序。
項目設(shè)計思路
1、Bezier曲線介紹:
貝塞爾曲線就是這樣的一條曲線,它是依據(jù)四個位置任意的點坐標(biāo)繪制出的一條光滑曲線。在歷史上,研究貝塞爾曲線的人最初是按照已知曲線參數(shù)方程來確定四個點的思路設(shè)計出這種矢量曲線繪制法。1962年,法國數(shù)學(xué)家Pierre Bézier第一個研究了這種矢量繪制曲線的方法,并給出了詳細(xì)的計算公式,因此按照這樣的公式繪制出來的曲線就用他的姓氏來命名是為貝塞爾曲線。
2、生成公式:
(1)線性公式(只有兩個點情況)
給定點P0、P1,線性貝茲曲線只是一條兩點之間的直線。這條線由下式給出:
且其等同于線性插值。
(2)二次方公式(三個點組成)
二次方貝茲曲線的路徑由給定點P0、P1、P2的函數(shù)B(t)追蹤:
TrueType字型就運用了以貝茲樣條組成的二次貝茲曲線。
(3)三次方公式(四個點)
P0、P1、P2、P3四個點在平面或在三維空間中定義了三次方貝茲曲線。曲線起始于P0走向P1,并從P2的方向來到P3。一般不會經(jīng)過P1或P2;這兩個點只是在那里提供方向資訊。P0和P1之間的間距,決定了曲線在轉(zhuǎn)而趨進(jìn)P3之前,走向P2方向的“長度有多長”。
曲線的參數(shù)形式為:
現(xiàn)代的成象系統(tǒng),如PostScript、Asymptote和Metafont,運用了以貝茲樣條組成的三次貝茲曲線,用來描繪曲線輪廓。
(4)一般參數(shù)公式(n個點)
階貝茲曲線可如下推斷。給定點P0、P1、…、Pn,其貝茲曲線即:
N階的貝茲曲線,即N-1階貝茲曲線之間的插值。
#include<stdlib.h> #include<stdio.h> #include<math.h> #include<GL/glut.h> //定義控制點數(shù)目的最大值 #define MAX_CPTX 25 int ncpts=0;//實際控制點個數(shù) static int width=600,height=600;//窗口大小 typedef struct { GLfloat x,y; } POINT; POINT cpts[MAX_CPTX];//存儲控制點坐標(biāo) //求n! int JieCheng(int n) { if(n==1||n==0) { return 1; } else { return n*JieCheng(n-1); } } //求組合排列 double C(int n,int i) { return ((double)JieCheng(n))/((double)(JieCheng(i)*JieCheng(n-i))); } //求一個數(shù)u的num次方 double N(double u,int n) { double sum=1.0; if (n==0) { return 1; } for(int i=0;i<n;i++) { sum*=u; } return sum; } //繪制bezier曲線 void drawBezier(POINT *p) { void display(); if(ncpts<=0) return; POINT *p1; p1=new POINT[1000]; GLfloat u=0,x,y; int i,num=1; p1[0]=p[0]; for(u=0;u<=1;u=u+0.001) { x=0; y=0; for(i=0;i<ncpts;i++) { x+=C(ncpts-1,i)*N(u,i)*N((1-u),(ncpts-1-i))*p[i].x; y+=C(ncpts-1,i)*N(u,i)*N((1-u),(ncpts-1-i))*p[i].y; } p1[num].x=x; p1[num].y=y; num++; } glPointSize(4.0); glColor3f(0.0,0.0,0.0); glBegin(GL_LINE_STRIP); for(int k=0;k<1000;k++) glVertex2f(p1[k].x,p1[k].y); glEnd(); glFlush(); return; } //輸入新的控制點 static void mouse(int button, int state,int x,int y) { void display(); float wx,wy; //鼠標(biāo)未按下左鍵,不做響應(yīng) if(state!=GLUT_DOWN) return; else {if(button==GLUT_LEFT_BUTTON) { //轉(zhuǎn)換坐標(biāo) wx=(2.0*x)/(float)(width-1)-1.0; wy=(2.0*(height-1-y))/(float)(height-1)-1.0; //判斷控制點數(shù)目是否超過最大值 if(ncpts==MAX_CPTX) return; //存儲控制點 cpts[ncpts].x=wx; cpts[ncpts].y=wy; ncpts++; //繪制控制點 glColor3f(0.0,0.0,0.0); glPointSize(5.0); glBegin(GL_POINTS); glVertex2f(wx,wy); glEnd(); glFlush(); } if(button==GLUT_RIGHT_BUTTON) { display(); drawBezier(cpts); } } } void display(void) { int i; glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0,0.0,0.0); glPointSize(5.0); glBegin(GL_POINTS); for (i = 0; i < ncpts; i++) glVertex2f(cpts[i].x,cpts[i].y); glEnd(); glFlush(); } //鍵盤回調(diào)函數(shù) void keyboard(unsigned char key,int x,int y) { switch (key) { case 'q': case 'Q': exit(0); break; case 'c': case 'C': ncpts = 0; glutPostRedisplay(); break; case 'r': case 'R': ncpts--; glutPostRedisplay(); break; } } //重繪函數(shù) void reshape(int w,int h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0); glMatrixMode(GL_MODELVIEW); glViewport(0,0,w,h);//調(diào)整視口 width=w; height=h; } int main(int argc, char **argv) { //初始化 glutInit(&argc,argv); glutInitDisplayMode(GLUT_RGB); glutInitWindowSize(width,height); glutCreateWindow("zjc2012211763"); //注冊回調(diào)函數(shù) glutDisplayFunc(display); glutMouseFunc(mouse); glutKeyboardFunc(keyboard); glutReshapeFunc(reshape); glClearColor(1.0,1.0,1.0,1.0); glColor3f(0.0,0.0,0.0); glutMainLoop(); }
看完上述內(nèi)容,是不是對OpenGL如何繪制Bezier曲線有進(jìn)一步的了解,如果還想學(xué)習(xí)更多內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。