基於OpenGL實現多段Bezier曲線拼接
阿新 • • 發佈:2020-04-22
本文例項為大家分享了OpenGL實現多段Bezier曲線拼接的具體程式碼,供大家參考,具體內容如下
執行程式的互動方式有點類似corelDraw中的自由曲線繪製,或者photoShop中的鋼筆自由路徑繪製。
截圖:
將BezierCurve封裝成了一個類,程式碼如下:
#ifndef _BEZIERCURVE_H #define _BEZIERCURVE_H #include "vec3.hpp" #include <vector> #include <iostream> #include <gl/glut.h> using namespace std; //// 3次bezier曲線: 四個控制節點。曲線經過首末兩個頂點。 class BezierCurve { public: //cell一共有四個控制頂點 // -cell經過V0和V3頂點, // -cell的始端相切於直線:(V0,V1) 和末端相切於(V2,V3) class BezierCell { public: BezierCell(int i0,int i1,int i2,int i3) { setValue(i0,i1,i2,i3); } void setValue(int i0,int i3) { ctrlVertxIndex[0] = i0; ctrlVertxIndex[1] = i1; ctrlVertxIndex[2] = i2; ctrlVertxIndex[3] = i3; } const int operator[](int index) const { if (index > 3 || index < 0) return -1; return ctrlVertxIndex[index]; } int ctrlVertxIndex[4]; }; enum eventType { LButtonDown = 0,MouseMove = 1,LButtonUp = 2 }; enum { Bezier3CtrlPnt = 4 }; BezierCurve() { clear(); } ~BezierCurve(){} void begin() { // 開啟求值器 glEnable(GL_MAP1_VERTEX_3); clear(); } void mouseSynchro(eventType type,const Vec3d& v) //響應滑鼠motion { ////////////////////////////////////////////////////////////////////////// //LButtonDown: 壓入點 if (type == LButtonDown) { if (isFirstRender) //for the first cell { vertexVector.push_back(v); //push V0... vertexVector.push_back(v); //push V1... } else if ( cellRenderState() == cellRenderImple::Push ) //for any cell { vertexVector.push_back(v); //push V2... vertexVector.push_back(v); //push V3... cellRenderState.setChange(); //set the flag to change V3 cellNum++; //increase the cell counter } } ////////////////////////////////////////////////////////////////////////// //MouseMove: 動態更新相應的頂點資料 else if (type == MouseMove) { if (isFirstRender) //for the first cell { vertexVector.back() = v; //change the V1 immediately } else if ( cellRenderState() == cellRenderImple::Change )//for any cell { int vecSize = vertexVector.size(); vertexVector[vecSize-2] = v; //change the V2 immediately } } ////////////////////////////////////////////////////////////////////////// //LButtonUp: 為拼接做準備 else if (type == LButtonUp) { if (isFirstRender) { //只有第一個BezierCell可以編輯bezierCell的起始段:(V0,V1) isFirstRender = false; } else if ( cellRenderState() == cellRenderImple::Change) { //if finish the current cell's render //利用v1和中點v0計算出v2:(v1 + v2) / 2 = v0 //next cell begin: push the next cell's V1... int vecSize = vertexVector.size(); Vec3d v0 = vertexVector[vecSize-1]; Vec3d v1 = vertexVector[vecSize-2]; Vec3d v2 = 2 * v0 - v1; vertexVector.push_back(v2); //重置cellRenderFlag cellRenderState.setPush(); } } ////////////////////////////////////////////////////////////////////////// //更新陣列的長度 _updateVertexNum(); } void end() { glDisable(GL_MAP1_VERTEX_3); } void renderCurve() { ////////////////////////////////////////////////////////////////////////// //rendering vertex... for (int i=0; i<vertexVector.size(); i++) { Vec3d v = vertexVector[i]; glBegin(GL_POINTS); glVertex3dv(v.getValue()); glEnd(); } ////////////////////////////////////////////////////////////////////////// //rendering moving tangent(切線) //(vertexNum-1,vertexNum-2) if ( vertexNum>=2 ) { glEnable(GL_LINE_STIPPLE); { glLineStipple(1,0x0101); glBegin(GL_LINES); { Vec3d v1 = vertexVector[vertexNum-1]; Vec3d v2 = vertexVector[vertexNum-2]; glVertex3dv(v1.getValue()); glVertex3dv(v2.getValue()); } glEnd(); }glDisable(GL_LINE_STIPPLE); } ////////////////////////////////////////////////////////////////////////// //if ( !_check() ) // return; //rendering bezier cells... system("CLS"); for (int i=0; i<cellNum; i++) { int pos = i * 3; if ( (pos+3) < vertexNum ) renderBezierCell( BezierCell(pos,pos+1,pos+2,pos+3) ); } ////////////////////////////////////////////////////////////////////////// } // 3次bezier曲線經過vetex0和vextex3 void renderBezierCell(const BezierCell& cell) { double *pBuffer = new double[Bezier3CtrlPnt * 3]; cout << "----------------------------------------------------" << endl; cout << "Vertex number : " << vertexNum << endl; cout << "Cell number : " << cellNum << endl; cout << "The render cell: " << cell[0] << " " << cell[1] << " " << cell[2] << " " << cell[3] << endl; for (int i = 0,bg = 0; i<4; i++) { Vec3d v = vertexVector[ cell[i] ]; pBuffer[bg++] = v.x(); pBuffer[bg++] = v.y(); pBuffer[bg++] = v.z(); cout << v.x() << " " << v.y() << " " << v.z() << endl; }cout << "----------------------------------------------------" << endl; glMap1d(GL_MAP1_VERTEX_3,0.0,1.0,3,Bezier3CtrlPnt,pBuffer); glBegin(GL_LINE_STRIP); { for (int i = 0; i <= 30; i++) glEvalCoord1f((GLfloat) i/30.0f); } glEnd(); delete pBuffer; pBuffer = 0; } void clear() { cellNum = 0; vertexNum = 0; isFirstRender = true; vertexVector.clear(); } protected: bool _check() { vertexNum =vertexVector.size(); return vertexNum == (cellNum - 1) * 3 + 4; } void _updateVertexNum() { vertexNum=vertexVector.size();} int cellNum; //單元個數 int vertexNum; //頂點個數 bool isFirstRender; //首次標誌 std::vector<Vec3d> vertexVector; //頂點陣列 class cellRenderImple { public: enum RenderStep { Push = 0,Change = 1 }; cellRenderImple(){ setPush(); } bool operator()(void) { return flag; } void setPush() { flag = Push; } void setChange() { flag = Change; } RenderStep flag; //cell的渲染狀態 } cellRenderState; };
測試程式如下:
#include <iostream> #include <vector> #include <GL/glut.h> #include "BezierCurve.h" using namespace std; enum WindowSize{ WinWidth = 1024,WinHeight = 768 }; int g_Viewport[4]; double g_ModelMatrix[16]; double g_ProjMatrix[16]; BezierCurve myBezier; ////////////////////////////////////////////////////////////////////////// void init(); void display(); void reshape(int w,int h); void keyboard(unsigned char key,int x,int y); void mouse(int button,int state,int y); void motion(int x,int y); int main(int argc,char** argv) { glutInit(&argc,argv); glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize (WinWidth,WinHeight); glutInitWindowPosition (100,100); glutCreateWindow (argv[0]); 以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。 init (); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc (keyboard); glutMouseFunc(mouse); glutMotionFunc(motion); glutMainLoop(); return 0; } void init(void) { glClearColor(0.0,0.0); glShadeModel(GL_SMOOTH); myBezier.begin(); } void display(void) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0,0.0); glPointSize(5.0); glPushMatrix(); { myBezier.renderCurve(); }glPopMatrix(); glutSwapBuffers(); } void reshape(int w,int h) { glViewport(0,(GLsizei) w,(GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-5.0,5.0,-5.0*(GLfloat)h/(GLfloat)w,5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0); else glOrtho(-5.0*(GLfloat)w/(GLfloat)h,5.0*(GLfloat)w/(GLfloat)h,5.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void keyboard(unsigned char key,int y) { switch (key) { case 27: exit(0); break; } } void mouse(int button,int y) { double vertex[3]; //獲取矩陣資訊 glGetIntegerv(GL_VIEWPORT,g_Viewport); glGetDoublev(GL_MODELVIEW_MATRIX,g_ModelMatrix); glGetDoublev(GL_PROJECTION_MATRIX,g_ProjMatrix); y = g_Viewport[3] - y; gluUnProject( x,y,g_ModelMatrix,g_ProjMatrix,g_Viewport,&vertex[0],&vertex[1],&vertex[2] ); if (button==GLUT_LEFT && state==GLUT_DOWN) { myBezier.mouseSynchro( BezierCurve::LButtonDown,vertex ); glutSetCursor( GLUT_CURSOR_RIGHT_ARROW ); } else if (button == GLUT_LEFT && state == GLUT_UP) { myBezier.mouseSynchro( BezierCurve::LButtonUp,vertex ); } glutPostRedisplay(); } ////////////////////////////////////////////////////////////////////////// // 計算控制節點 void motion(int x,int y) { double vertex[3]; glutSetCursor( GLUT_CURSOR_CROSSHAIR ); y = g_Viewport[3] - y; gluUnProject( x,&vertex[2] ); myBezier.mouseSynchro( BezierCurve::MouseMove,vertex ); glutPostRedisplay(); }
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。