本文实例为大家分享了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://blog.csdn.net/ryfdizuo/article/details/4728785