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

时间:2022-09-20 23:59:51

本文实例为大家分享了OpenGL实现多段Bezier曲线拼接的具体代码,供大家参考,具体内容如下

运行程序的交互方式有点类似corelDraw中的*曲线绘制,或者photoShop中的钢笔*路径绘制。

截图:

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

将BezierCurve封装成了一个类,代码如下:

  1. #ifndef _BEZIERCURVE_H
  2. #define _BEZIERCURVE_H
  3.  
  4. #include "vec3.hpp"
  5. #include <vector>
  6. #include <iostream>
  7. #include <gl/glut.h>
  8.  
  9. using namespace std;
  10. //// 3次bezier曲线: 四个控制节点。曲线经过首末两个顶点。
  11.  
  12. class BezierCurve
  13. {
  14. public:
  15. //cell一共有四个控制顶点
  16. // -cell经过V0和V3顶点,
  17. // -cell的始端相切于直线:(V0, V1) 和末端相切于(V2,V3)
  18. class BezierCell
  19. {
  20. public:
  21. BezierCell(int i0, int i1, int i2, int i3)
  22. {
  23. setValue(i0, i1, i2, i3);
  24. }
  25.  
  26. void setValue(int i0, int i1, int i2, int i3)
  27. {
  28. ctrlVertxIndex[0] = i0;
  29. ctrlVertxIndex[1] = i1;
  30. ctrlVertxIndex[2] = i2;
  31. ctrlVertxIndex[3] = i3;
  32. }
  33. const int operator[](int index) const
  34. {
  35. if (index > 3 || index < 0)
  36. return -1;
  37.  
  38. return ctrlVertxIndex[index];
  39. }
  40. int ctrlVertxIndex[4];
  41. };
  42.  
  43. enum eventType
  44. {
  45. LButtonDown = 0,
  46. MouseMove = 1,
  47. LButtonUp = 2
  48. };
  49.  
  50. enum { Bezier3CtrlPnt = 4 };
  51.  
  52. BezierCurve() { clear(); }
  53. ~BezierCurve(){}
  54.  
  55. void begin()
  56. {
  57. // 开启求值器
  58. glEnable(GL_MAP1_VERTEX_3);
  59. clear();
  60. }
  61.  
  62. void mouseSynchro(eventType type, const Vec3d& v) //响应鼠标motion
  63. {
  64. //////////////////////////////////////////////////////////////////////////
  65. //LButtonDown: 压入点
  66. if (type == LButtonDown)
  67. {
  68. if (isFirstRender) //for the first cell
  69. {
  70. vertexVector.push_back(v); //push V0...
  71. vertexVector.push_back(v); //push V1...
  72. }
  73. else if ( cellRenderState() == cellRenderImple::Push ) //for any cell
  74. {
  75. vertexVector.push_back(v); //push V2...
  76. vertexVector.push_back(v); //push V3...
  77.  
  78. cellRenderState.setChange(); //set the flag to change V3
  79. cellNum++; //increase the cell counter
  80. }
  81. }
  82. //////////////////////////////////////////////////////////////////////////
  83. //MouseMove: 动态更新相应的顶点数据
  84. else if (type == MouseMove)
  85. {
  86. if (isFirstRender) //for the first cell
  87. {
  88. vertexVector.back() = v; //change the V1 immediately
  89. }
  90. else if ( cellRenderState() == cellRenderImple::Change )//for any cell
  91. {
  92. int vecSize = vertexVector.size();
  93. vertexVector[vecSize-2] = v; //change the V2 immediately
  94. }
  95. }
  96.  
  97. //////////////////////////////////////////////////////////////////////////
  98. //LButtonUp: 为拼接做准备
  99. else if (type == LButtonUp)
  100. {
  101. if (isFirstRender)
  102. {
  103. //只有第一个BezierCell可以编辑bezierCell的起始段:(V0,V1)
  104. isFirstRender = false;
  105. }
  106. else if ( cellRenderState() == cellRenderImple::Change)
  107. {
  108. //if finish the current cell's render
  109. //利用v1和中点v0计算出v2:(v1 + v2) / 2 = v0
  110. //next cell begin: push the next cell's V1...
  111. int vecSize = vertexVector.size();
  112. Vec3d v0 = vertexVector[vecSize-1];
  113. Vec3d v1 = vertexVector[vecSize-2];
  114. Vec3d v2 = 2 * v0 - v1;
  115. vertexVector.push_back(v2);
  116.  
  117. //重置cellRenderFlag
  118. cellRenderState.setPush();
  119. }
  120. }
  121. //////////////////////////////////////////////////////////////////////////
  122. //更新数组的长度
  123. _updateVertexNum();
  124. }
  125.  
  126. void end()
  127. {
  128. glDisable(GL_MAP1_VERTEX_3);
  129. }
  130.  
  131. void renderCurve()
  132. {
  133. //////////////////////////////////////////////////////////////////////////
  134. //rendering vertex...
  135. for (int i=0; i<vertexVector.size(); i++)
  136. {
  137. Vec3d v = vertexVector[i];
  138. glBegin(GL_POINTS);
  139. glVertex3dv(v.getValue());
  140. glEnd();
  141. }
  142.  
  143. //////////////////////////////////////////////////////////////////////////
  144. //rendering moving tangent(切线)
  145. //(vertexNum-1, vertexNum-2)
  146. if ( vertexNum>=2 )
  147. {
  148. glEnable(GL_LINE_STIPPLE);
  149. {
  150. glLineStipple(1, 0x0101);
  151. glBegin(GL_LINES);
  152. {
  153. Vec3d v1 = vertexVector[vertexNum-1];
  154. Vec3d v2 = vertexVector[vertexNum-2];
  155. glVertex3dv(v1.getValue());
  156. glVertex3dv(v2.getValue());
  157. } glEnd();
  158. }glDisable(GL_LINE_STIPPLE);
  159. }
  160.  
  161. //////////////////////////////////////////////////////////////////////////
  162. //if ( !_check() )
  163. // return;
  164.  
  165. //rendering bezier cells...
  166. system("CLS");
  167. for (int i=0; i<cellNum; i++)
  168. {
  169. int pos = i * 3;
  170. if ( (pos+3) < vertexNum )
  171. renderBezierCell( BezierCell(pos, pos+1, pos+2, pos+3) );
  172. }
  173. //////////////////////////////////////////////////////////////////////////
  174. }
  175.  
  176. // 3次bezier曲线经过vetex0和vextex3
  177. void renderBezierCell(const BezierCell& cell)
  178. {
  179. double *pBuffer = new double[Bezier3CtrlPnt * 3];
  180.  
  181. cout << "----------------------------------------------------" << endl;
  182.  
  183. cout << "Vertex number : " << vertexNum << endl;
  184. cout << "Cell number : " << cellNum << endl;
  185. cout << "The render cell: " << cell[0] << " " << cell[1] << " " << cell[2] << " " << cell[3] << endl;
  186.  
  187. for (int i = 0, bg = 0; i<4; i++)
  188. {
  189. Vec3d v = vertexVector[ cell[i] ];
  190. pBuffer[bg++] = v.x();
  191. pBuffer[bg++] = v.y();
  192. pBuffer[bg++] = v.z();
  193.  
  194. cout << v.x() << " " << v.y() << " " << v.z() << endl;
  195. }cout << "----------------------------------------------------" << endl;
  196.  
  197. glMap1d(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, Bezier3CtrlPnt, pBuffer);
  198. glBegin(GL_LINE_STRIP);
  199. {
  200. for (int i = 0; i <= 30; i++)
  201. glEvalCoord1f((GLfloat) i/30.0f);
  202. } glEnd();
  203.  
  204. delete pBuffer; pBuffer = 0;
  205. }
  206.  
  207. void clear()
  208. {
  209. cellNum = 0;
  210. vertexNum = 0;
  211.  
  212. isFirstRender = true;
  213.  
  214. vertexVector.clear();
  215. }
  216. protected:
  217. bool _check() { vertexNum =vertexVector.size();
  218. return vertexNum == (cellNum - 1) * 3 + 4; }
  219. void _updateVertexNum() { vertexNum=vertexVector.size();}
  220.  
  221. int cellNum; //单元个数
  222. int vertexNum; //顶点个数
  223.  
  224. bool isFirstRender; //首次标志
  225. std::vector<Vec3d> vertexVector; //顶点数组
  226.  
  227. class cellRenderImple
  228. {
  229. public:
  230. enum RenderStep
  231. {
  232. Push = 0,
  233. Change = 1
  234. };
  235. cellRenderImple(){ setPush(); }
  236. bool operator()(void) { return flag; }
  237. void setPush() { flag = Push; }
  238. void setChange() { flag = Change; }
  239.  
  240. RenderStep flag; //cell的渲染状态
  241. } cellRenderState;
  242. };

测试程序如下:

  1. #include <iostream>
  2. #include <vector>
  3. #include <GL/glut.h>
  4.  
  5. #include "BezierCurve.h"
  6.  
  7. using namespace std;
  8.  
  9. enum WindowSize{
  10. WinWidth = 1024,
  11. WinHeight = 768
  12. };
  13.  
  14. int g_Viewport[4];
  15. double g_ModelMatrix[16];
  16. double g_ProjMatrix[16];
  17. BezierCurve myBezier;
  18.  
  19. //////////////////////////////////////////////////////////////////////////
  20. void init();
  21. void display();
  22. void reshape(int w, int h);
  23. void keyboard(unsigned char key, int x, int y);
  24. void mouse(int button, int state, int x, int y);
  25. void motion(int x, int y);
  26.  
  27. int main(int argc, char** argv)
  28. {
  29. glutInit(&argc, argv);
  30. glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
  31. glutInitWindowSize (WinWidth, WinHeight);
  32. glutInitWindowPosition (100, 100);
  33. glutCreateWindow (argv[0]);
  34.  
  35. 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
  36.  
  37. init ();
  38. glutDisplayFunc(display);
  39. glutReshapeFunc(reshape);
  40. glutKeyboardFunc (keyboard);
  41. glutMouseFunc(mouse);
  42. glutMotionFunc(motion);
  43.  
  44. glutMainLoop();
  45.  
  46. return 0;
  47. }
  48.  
  49. void init(void)
  50. {
  51. glClearColor(0.0, 0.0, 0.0, 0.0);
  52. glShadeModel(GL_SMOOTH);
  53.  
  54. myBezier.begin();
  55. }
  56.  
  57. void display(void)
  58. {
  59. glClear(GL_COLOR_BUFFER_BIT);
  60.  
  61. glColor3f(1.0, 1.0, 0.0);
  62. glPointSize(5.0);
  63.  
  64. glPushMatrix();
  65. {
  66. myBezier.renderCurve();
  67. }glPopMatrix();
  68.  
  69. glutSwapBuffers();
  70. }
  71.  
  72. void reshape(int w, int h)
  73. {
  74. glViewport(0, 0, (GLsizei) w, (GLsizei) h);
  75. glMatrixMode(GL_PROJECTION);
  76. glLoadIdentity();
  77. if (w <= h)
  78. glOrtho(-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w,
  79. 5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0);
  80. else
  81. glOrtho(-5.0*(GLfloat)w/(GLfloat)h,
  82. 5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0);
  83. glMatrixMode(GL_MODELVIEW);
  84. glLoadIdentity();
  85. }
  86.  
  87. void keyboard(unsigned char key, int x, int y)
  88. {
  89. switch (key) {
  90. case 27:
  91. exit(0);
  92. break;
  93. }
  94. }
  95.  
  96. void mouse(int button, int state, int x, int y)
  97. {
  98. double vertex[3];
  99.  
  100. //获取矩阵信息
  101. glGetIntegerv(GL_VIEWPORT, g_Viewport);
  102. glGetDoublev(GL_MODELVIEW_MATRIX, g_ModelMatrix);
  103. glGetDoublev(GL_PROJECTION_MATRIX, g_ProjMatrix);
  104.  
  105. y = g_Viewport[3] - y;
  106. gluUnProject( x, y, 0,
  107. g_ModelMatrix, g_ProjMatrix, g_Viewport,
  108. &vertex[0], &vertex[1], &vertex[2] );
  109.  
  110. if (button==GLUT_LEFT && state==GLUT_DOWN)
  111. {
  112. myBezier.mouseSynchro( BezierCurve::LButtonDown, vertex );
  113. glutSetCursor( GLUT_CURSOR_RIGHT_ARROW );
  114. }
  115. else if (button == GLUT_LEFT && state == GLUT_UP)
  116. {
  117. myBezier.mouseSynchro( BezierCurve::LButtonUp, vertex );
  118. }
  119.  
  120. glutPostRedisplay();
  121. }
  122.  
  123. //////////////////////////////////////////////////////////////////////////
  124. // 计算控制节点
  125. void motion(int x, int y)
  126. {
  127. double vertex[3];
  128.  
  129. glutSetCursor( GLUT_CURSOR_CROSSHAIR );
  130. y = g_Viewport[3] - y;
  131.  
  132. gluUnProject( x, y, 0,
  133. g_ModelMatrix, g_ProjMatrix, g_Viewport,
  134. &vertex[0], &vertex[1], &vertex[2] );
  135.  
  136. myBezier.mouseSynchro( BezierCurve::MouseMove, vertex );
  137. glutPostRedisplay();
  138. }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

原文链接:https://blog.csdn.net/ryfdizuo/article/details/4728785