您好,登錄后才能下訂單哦!
小編這次要給大家分享的是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 i1, int i2, 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 x, 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, 0.0, 0.0); glShadeModel(GL_SMOOTH); myBezier.begin(); } void display(void) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 0.0); glPointSize(5.0); glPushMatrix(); { myBezier.renderCurve(); }glPopMatrix(); glutSwapBuffers(); } void reshape(int w, int h) { glViewport(0, 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, 5.0, -5.0, 5.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void keyboard(unsigned char key, int x, int y) { switch (key) { case 27: exit(0); break; } } void mouse(int button, int state, int x, 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, 0, 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, y, 0, g_ModelMatrix, g_ProjMatrix, g_Viewport, &vertex[0], &vertex[1], &vertex[2] ); myBezier.mouseSynchro( BezierCurve::MouseMove, vertex ); glutPostRedisplay(); }
看完這篇關于OpenGL如何實現多段Bezier曲線拼接的文章,如果覺得文章內容寫得不錯的話,可以把它分享出去給更多人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。