本文实例为大家分享了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(); }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自学编程网。
- 本文固定链接: https://zxbcw.cn/post/185106/
- 转载请注明:必须在正文中标注并保留原文链接
- QQ群: PHP高手阵营官方总群(344148542)
- QQ群: Yii2.0开发(304864863)