基於OpenGL實現的多段Bezier曲線拼接

來源:互聯網
上載者:User

運行程式的互動方式有點類似corelDraw中的徒手畫繪製,或者photoShop中的鋼筆自由路徑繪製。

 

將BezierCurve封裝成了一個類,代碼如下:

 #ifndef _BEZIERCURVE_H<br />#define _BEZIERCURVE_H</p><p>#include "vec3.hpp"<br />#include <vector><br />#include <iostream><br />#include <gl/glut.h></p><p>using namespace std;<br />//// 3次bezier曲線: 四個控制節點。曲線經過首末兩個頂點。</p><p>class BezierCurve<br />{<br />public:<br />//cell一共有四個控制頂點<br />//-cell經過V0和V3頂點,<br />//-cell的始端相切於直線:(V0, V1) 和末端相切於(V2,V3)<br />class BezierCell<br />{<br />public:<br />BezierCell(int i0, int i1, int i2, int i3)<br />{<br />setValue(i0, i1, i2, i3);<br />}</p><p>void setValue(int i0, int i1, int i2, int i3)<br />{<br />ctrlVertxIndex[0] = i0;<br />ctrlVertxIndex[1] = i1;<br />ctrlVertxIndex[2] = i2;<br />ctrlVertxIndex[3] = i3;<br />}<br />const int operator[](int index) const<br />{<br />if (index > 3 || index < 0)<br />return -1;</p><p>return ctrlVertxIndex[index];<br />}<br />int ctrlVertxIndex[4];<br />};</p><p>enum eventType<br />{<br />LButtonDown = 0,<br />MouseMove = 1,<br />LButtonUp = 2<br />};</p><p>enum { Bezier3CtrlPnt = 4 };</p><p>BezierCurve() { clear(); }<br />~BezierCurve(){}</p><p>void begin()<br />{<br />// 開啟求值器<br />glEnable(GL_MAP1_VERTEX_3);<br />clear();<br />}</p><p>void mouseSynchro(eventType type, const Vec3d& v)//響應滑鼠motion<br />{<br />//////////////////////////////////////////////////////////////////////////<br />//LButtonDown: 壓入點<br />if (type == LButtonDown)<br />{<br />if (isFirstRender)//for the first cell<br />{<br />vertexVector.push_back(v);//push V0...<br />vertexVector.push_back(v);//push V1...<br />}<br />else if ( cellRenderState() == cellRenderImple::Push )//for any cell<br />{<br />vertexVector.push_back(v);//push V2...<br />vertexVector.push_back(v);//push V3...</p><p>cellRenderState.setChange();//set the flag to change V3<br />cellNum++;//increase the cell counter<br />}<br />}<br />//////////////////////////////////////////////////////////////////////////<br />//MouseMove: 動態更新相應的頂點資料<br />else if (type == MouseMove)<br />{<br />if (isFirstRender)//for the first cell<br />{<br />vertexVector.back() = v;//change the V1 immediately<br />}<br />else if ( cellRenderState() == cellRenderImple::Change )//for any cell<br />{<br />int vecSize = vertexVector.size();<br />vertexVector[vecSize-2] = v;//change the V2 immediately<br />}<br />}</p><p>//////////////////////////////////////////////////////////////////////////<br />//LButtonUp: 為拼接做準備<br />else if (type == LButtonUp)<br />{<br />if (isFirstRender)<br />{<br />//只有第一個BezierCell可以編輯bezierCell的起始段:(V0,V1)<br />isFirstRender = false;<br />}<br />else if ( cellRenderState() == cellRenderImple::Change)<br />{<br />//if finish the current cell's render<br />//利用v1和中點v0計算出v2:(v1 + v2) / 2 = v0<br />//next cell begin: push the next cell's V1...<br />int vecSize = vertexVector.size();<br />Vec3d v0 = vertexVector[vecSize-1];<br />Vec3d v1 = vertexVector[vecSize-2];<br />Vec3d v2 = 2 * v0 - v1;<br />vertexVector.push_back(v2);</p><p>//重設cellRenderFlag<br />cellRenderState.setPush();<br />}<br />}<br />//////////////////////////////////////////////////////////////////////////<br />//更新數組的長度<br />_updateVertexNum();<br />}</p><p>void end()<br />{<br />glDisable(GL_MAP1_VERTEX_3);<br />}</p><p>void renderCurve()<br />{<br />//////////////////////////////////////////////////////////////////////////<br />//rendering vertex...<br />for (int i=0; i<vertexVector.size(); i++)<br />{<br />Vec3d v = vertexVector[i];<br />glBegin(GL_POINTS);<br />glVertex3dv(v.getValue());<br />glEnd();<br />}</p><p>//////////////////////////////////////////////////////////////////////////<br />//rendering moving tangent(切線)<br />//(vertexNum-1, vertexNum-2)<br />if ( vertexNum>=2 )<br />{<br />glEnable(GL_LINE_STIPPLE);<br />{<br />glLineStipple(1, 0x0101);<br />glBegin(GL_LINES);<br />{<br />Vec3d v1 = vertexVector[vertexNum-1];<br />Vec3d v2 = vertexVector[vertexNum-2];<br />glVertex3dv(v1.getValue());<br />glVertex3dv(v2.getValue());<br />} glEnd();<br />}glDisable(GL_LINE_STIPPLE);<br />}</p><p>//////////////////////////////////////////////////////////////////////////<br />//if ( !_check() )<br />//return;</p><p>//rendering bezier cells...<br />system("CLS");<br />for (int i=0; i<cellNum; i++)<br />{<br />int pos = i * 3;<br />if ( (pos+3) < vertexNum )<br />renderBezierCell( BezierCell(pos, pos+1, pos+2, pos+3) );<br />}<br />//////////////////////////////////////////////////////////////////////////<br />}</p><p>// 3次bezier曲線經過vetex0和vextex3<br />void renderBezierCell(const BezierCell& cell)<br />{<br />double *pBuffer = new double[Bezier3CtrlPnt * 3];</p><p>cout << "----------------------------------------------------" << endl;</p><p>cout << "Vertex number : " << vertexNum << endl;<br />cout << "Cell number : " << cellNum << endl;<br />cout << "The render cell: " << cell[0] << " " << cell[1] << " " << cell[2] << " " << cell[3] << endl;</p><p>for (int i = 0, bg = 0; i<4; i++)<br />{<br />Vec3d v = vertexVector[ cell[i] ];<br />pBuffer[bg++] = v.x();<br />pBuffer[bg++] = v.y();<br />pBuffer[bg++] = v.z();</p><p>cout << v.x() << " " << v.y() << " " << v.z() << endl;<br />}cout << "----------------------------------------------------" << endl;</p><p>glMap1d(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, Bezier3CtrlPnt, pBuffer);<br />glBegin(GL_LINE_STRIP);<br />{<br />for (int i = 0; i <= 30; i++)<br />glEvalCoord1f((GLfloat) i/30.0f);<br />} glEnd();</p><p>delete pBuffer; pBuffer = 0;<br />}</p><p>void clear()<br />{<br />cellNum = 0;<br />vertexNum = 0;</p><p>isFirstRender = true;</p><p>vertexVector.clear();<br />}<br />protected:<br />bool _check() {vertexNum =vertexVector.size();<br />return vertexNum == (cellNum - 1) * 3 + 4; }<br />void _updateVertexNum() { vertexNum=vertexVector.size();}</p><p>intcellNum;//單元個數<br />int vertexNum;//頂點個數</p><p>bool isFirstRender;//首次標誌<br />std::vector<Vec3d> vertexVector;//頂點數組</p><p>class cellRenderImple<br />{<br />public:<br />enum RenderStep<br />{<br />Push = 0,<br />Change = 1<br />};<br />cellRenderImple(){ setPush(); }<br />bool operator()(void) { return flag;}<br />void setPush() { flag = Push; }<br />void setChange() { flag = Change; }</p><p>RenderStep flag;//cell的渲染狀態<br />} cellRenderState;<br />}; 

 

測試程式如下:

#include <iostream><br />#include <vector><br />#include <GL/glut.h></p><p>#include "BezierCurve.h"</p><p>using namespace std;</p><p>enum WindowSize{<br />WinWidth = 1024,<br />WinHeight = 768<br />};</p><p>intg_Viewport[4];<br />doubleg_ModelMatrix[16];<br />doubleg_ProjMatrix[16];<br />BezierCurve myBezier;</p><p>//////////////////////////////////////////////////////////////////////////<br />void init();<br />void display();<br />void reshape(int w, int h);<br />void keyboard(unsigned char key, int x, int y);<br />void mouse(int button, int state, int x, int y);<br />void motion(int x, int y);</p><p>int main(int argc, char** argv)<br />{<br />glutInit(&argc, argv);<br />glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);<br />glutInitWindowSize (WinWidth, WinHeight);<br />glutInitWindowPosition (100, 100);<br />glutCreateWindow (argv[0]);</p><p>init ();<br />glutDisplayFunc(display);<br />glutReshapeFunc(reshape);<br />glutKeyboardFunc (keyboard);<br />glutMouseFunc(mouse);<br />glutMotionFunc(motion);</p><p>glutMainLoop();</p><p>return 0;<br />}</p><p>void init(void)<br />{<br />glClearColor(0.0, 0.0, 0.0, 0.0);<br />glShadeModel(GL_SMOOTH);</p><p>myBezier.begin();<br />}</p><p>void display(void)<br />{<br />glClear(GL_COLOR_BUFFER_BIT);</p><p>glColor3f(1.0, 1.0, 0.0);<br />glPointSize(5.0);</p><p>glPushMatrix();<br />{<br />myBezier.renderCurve();<br />}glPopMatrix();</p><p>glutSwapBuffers();<br />}</p><p>void reshape(int w, int h)<br />{<br />glViewport(0, 0, (GLsizei) w, (GLsizei) h);<br />glMatrixMode(GL_PROJECTION);<br />glLoadIdentity();<br />if (w <= h)<br />glOrtho(-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w,<br />5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0);<br />else<br />glOrtho(-5.0*(GLfloat)w/(GLfloat)h,<br />5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0);<br />glMatrixMode(GL_MODELVIEW);<br />glLoadIdentity();<br />}</p><p>void keyboard(unsigned char key, int x, int y)<br />{<br />switch (key) {<br /> case 27:<br /> exit(0);<br /> break;<br />}<br />}</p><p>void mouse(int button, int state, int x, int y)<br />{<br />double vertex[3];</p><p>//擷取矩陣資訊<br />glGetIntegerv(GL_VIEWPORT, g_Viewport);<br />glGetDoublev(GL_MODELVIEW_MATRIX, g_ModelMatrix);<br />glGetDoublev(GL_PROJECTION_MATRIX, g_ProjMatrix);</p><p>y = g_Viewport[3] - y;<br />gluUnProject( x, y, 0,<br />g_ModelMatrix, g_ProjMatrix, g_Viewport,<br />&vertex[0], &vertex[1], &vertex[2] );</p><p>if (button==GLUT_LEFT && state==GLUT_DOWN)<br />{<br />myBezier.mouseSynchro( BezierCurve::LButtonDown, vertex );<br />glutSetCursor( GLUT_CURSOR_RIGHT_ARROW );<br />}<br />else if (button == GLUT_LEFT && state == GLUT_UP)<br />{<br />myBezier.mouseSynchro( BezierCurve::LButtonUp, vertex );<br />}</p><p>glutPostRedisplay();<br />}</p><p>//////////////////////////////////////////////////////////////////////////<br />// 計算控制節點<br />void motion(int x, int y)<br />{<br />double vertex[3];</p><p>glutSetCursor( GLUT_CURSOR_CROSSHAIR );<br />y = g_Viewport[3] - y;</p><p>gluUnProject( x, y, 0,<br />g_ModelMatrix, g_ProjMatrix, g_Viewport,<br />&vertex[0], &vertex[1], &vertex[2] );</p><p>myBezier.mouseSynchro( BezierCurve::MouseMove, vertex );<br />glutPostRedisplay();<br />} 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.