OpenGL: 基于OpenGL实现的多段Bezier曲线拼接

来源:互联网 发布:mac launchpad 是什么 编辑:程序博客网 时间:2024/05/17 23:28

运行程序的交互方式有点类似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 V3cellNum++;//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);//重置cellRenderFlagcellRenderState.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和vextex3void 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();}intcellNum;//单元个数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};intg_Viewport[4];doubleg_ModelMatrix[16];doubleg_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);elseglOrtho(-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();}



0 0
原创粉丝点击