1. 程式人生 > >OpenGL 繪制B樣條曲線

OpenGL 繪制B樣條曲線

ember direction onexit cti target get 說明 spa glbegin

http://blog.csdn.net/yangtrees/article/details/9026411

繪制B樣條曲線:

技術分享圖片

#include <stdlib.h>

#include <GL/glut.h>
#pragma comment(lib,"glut32.lib")

//

#if 0
// the points of the curve - these are the same as the bezier curve
// points demonstrated in the bezier curve example.

float Points[4][3] = {
	{ 10,10
,0 }, { 5,10,2 }, { -5,0,0 }, {-10,5,-2} }; #define NUM_POINTS 4 // The following sets of 4 indices are the curves that need to // be drawn to create a clamped cubic b-spline. In total there // are 5 curve segments to draw. // // 0 0 0 1 // 0 0 1 2 // 0 1 2 3 // 1 2 3 3 // 2 3 3 3 // // Remember this when trying to understand knot vectors!!
// #else float Points[9][3] = { { 10,5,0 }, { 5,10,0 }, { -5,15,0 }, { -10,-5,0 }, { 4,-4,0 }, { 10,5,0 }, { 5,10,0 }, { -5,15,0 }, { -10,-5,0 } }; #define NUM_POINTS 9 //若繪制過首尾控制點的曲線 // 0 0 0 1 // 0 0 1 2 // 0 1 2 3 // 1 2 3 4 // 2 3 4 5 // 3 4 5 6 // 4 5 6 6 // 5 6 6 6 // // Remember this when trying to understand knot vectors!!
// //若繪制首尾相接的平滑曲線 ,即為當前繪制 // 0 1 2 3 // 1 2 3 4 // 2 3 4 5 // 3 4 5 6 #endif // the level of detail for the curve unsigned int LOD=20; #define NUM_SEGMENTS (NUM_POINTS-3) // float* GetPoint(int i) { // return 1st point if (i<0) { return Points[0]; } if (i<NUM_POINTS) { return Points[i]; } // return last point return Points[NUM_POINTS-1]; } //------------------------------------------------------------ OnKeyPress() void myIdle(void) { glutPostRedisplay(); } //------------------------------------------------------------ OnDraw() void OnDraw() { // clear the screen & depth buffer glClear(GL_COLOR_BUFFER_BIT); // clear the previous transform glLoadIdentity(); // set the camera position // gluLookAt( 1,10,30, // eye pos // 0,0,0, // aim point // 0,1,0); // up direction // glColor3f(0.5,0.2,0); glPointSize(3); // // // draw curve hull glColor3f(0.3,0,0.5); glBegin(GL_LINE_STRIP); for(int i=0;i!=NUM_POINTS;++i) { glVertex3fv( Points[i] ); } glEnd(); glColor3f(0,1,0); // begin drawing our curve glBegin(GL_LINE_STRIP); for(int start_cv=0,j=0;j<NUM_SEGMENTS;j++,start_cv++) { // for each section of curve, draw LOD number of divisions for(int i=0;i!=LOD;++i) { // use the parametric time value 0 to 1 for this curve // segment. float t = (float)i/LOD; // the t value inverted float it = 1.0f-t; // calculate blending functions for cubic bspline float b0 = it*it*it/6.0f; float b1 = (3*t*t*t - 6*t*t +4)/6.0f; float b2 = (-3*t*t*t +3*t*t + 3*t + 1)/6.0f; float b3 = t*t*t/6.0f; // calculate the x,y and z of the curve point float x = b0 * GetPoint( start_cv + 0 )[0] + b1 * GetPoint( start_cv + 1 )[0] + b2 * GetPoint( start_cv + 2 )[0] + b3 * GetPoint( start_cv + 3 )[0] ; float y = b0 * GetPoint( start_cv + 0 )[1] + b1 * GetPoint( start_cv + 1 )[1] + b2 * GetPoint( start_cv + 2 )[1] + b3 * GetPoint( start_cv + 3 )[1] ; float z = b0 * GetPoint( start_cv + 0 )[2] + b1 * GetPoint( start_cv + 1 )[2] + b2 * GetPoint( start_cv + 2 )[2] + b3 * GetPoint( start_cv + 3 )[2] ; // specify the point glVertex2f( x,y ); } } // we need to specify the last point on the curve //glVertex3fv( Points[NUM_POINTS-1] ); glEnd(); // draw CV‘s glBegin(GL_POINTS); for(int i=0;i!=NUM_POINTS;++i) { glVertex3fv( Points[i] ); } glEnd(); // currently we‘ve been drawing to the back buffer, we need // to swap the back buffer with the front one to make the image visible glutSwapBuffers(); } //------------------------------------------------------------ OnInit() void OnInit() { //glClearColor(1,1,1,0); } //------------------------------------------------------------ OnExit() void OnExit() { } //------------------------------------------------------------ OnReshape() void OnReshape(int w, int h) { // prevents division by zero when minimising window if (h==0) { h=1; } // set the drawable region of the window glViewport(0,0,w,h); // set up the projection matrix glMatrixMode(GL_PROJECTION); glLoadIdentity(); // just use a perspective projection //gluPerspective(45,(float)w/h,0.1,100); if(w<=h) { glOrtho(-20.0,20.0,-20.0*(GLfloat)h/(GLfloat)w,20.0*(GLfloat)h/(GLfloat)w,0.0,100.0); } else { glOrtho(-20.0,20.0,-20.0*(GLfloat)h/(GLfloat)w,20.0*(GLfloat)h/(GLfloat)w,0.0,100.0); } // go back to modelview matrix so we can move the objects about glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } //------------------------------------------------------------ main() int main(int argc,char** argv) { // initialise glut glutInit(&argc,argv); // request a depth buffer, RGBA display mode, and we want double buffering glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE); // set the initial window size glutInitWindowSize(640,480); // create the window glutCreateWindow("Clamped B-Spline Curve"); // run our custom initialisation OnInit(); // set the function to use to draw our scene glutDisplayFunc(OnDraw); // set the function to handle changes in screen size glutReshapeFunc(OnReshape); glutIdleFunc(&myIdle); // set the function to be called when we exit atexit(OnExit); // this function runs a while loop to keep the program running. glutMainLoop(); return 0; }

closed-B樣條:

技術分享圖片

Reference:

B樣條詳細說明:

http://blog.csdn.net/tuqu/article/details/5366701

繪制closed-B樣條曲線

http://blog.csdn.net/tuqu/article/details/5386215

OpenGL繪制DDA、Hermite、Bezier、B樣條:

http://blog.163.com/zhou_ghui/blog/static/177580120132159441827/

<1>DDA直線:(兩點確定一條曲線,即用鼠標點兩點);

#include <windows.h>
#include <stdio.h>
#include <math.h>

#include <gl/glut.h>
#pragma comment(lib,"glut32.lib")

GLfloat x_coord[2], y_coord[2];
int nPoints = 0;
inline GLfloat x_convert (int x)
{
	return -8.0+x/499.0*16;
}
inline GLfloat y_convert (int y)
{
	return 8.0 - y/499.0*16;
}
void init(){
	glClearColor(1,1,1,0);
}
void myReshape(int w,int h)
{
	glViewport(0,0,(GLsizei)w,(GLsizei)h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	//gluPerspective(45.0,(GLfloat)w/(GLfloat)h,1.0,50.0);
	if(w<=h)
		glOrtho(-8.0,8.0,-8.0*(GLfloat)h/(GLfloat)w,8.0*(GLfloat)h/(GLfloat)w,-8.0,8.0);
	else
		glOrtho(-8.0*(GLfloat)h/(GLfloat)w,8.0*(GLfloat)h/(GLfloat)w,-8.0,8.0,-8.0,8.0);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}
int round ( float a){
	return int (a+0.5);
}
void DDA(int x0,int xEnd,int y0, int yEnd)  //DDA畫線算法
{
	float dx= xEnd - x0 ;
	float dy= yEnd - y0 ;
	int steps ;
	float xIncrement , yIncrement , x=x0, y=y0;
	if(fabs(dx) > fabs(dy) )
		steps = fabs (dx);
	else steps = fabs(dy);

	xIncrement = (float) dx/steps;
	yIncrement = (float) dy/steps;

	glBegin(GL_POINTS);
	glPointSize(100);
	glVertex2i( round (x), round (y));
	for(int i=0; i < steps; i++)
	{
		x+=xIncrement;
		y+=yIncrement;
		glVertex2i( round (x), round (y));
	}
	glEnd();
  }
  void display(){
	  glClear(GL_COLOR_BUFFER_BIT);

	  glColor3f(0,1,0);                //畫兩點之間的直線
	  glBegin(GL_LINE_STRIP);
	  for (int i = 0; i < nPoints; i++)
		  glVertex3f (x_coord[i], y_coord[i], 0.0);
	  glEnd();

	  glColor3f (1.0, 0, 0);            //調用DDA畫線算法
	  glPointSize(5);
	  if (nPoints == 2)
		  DDA(x_coord[0],x_coord[1], y_coord[0] , y_coord[1]);

	  glFlush();

  }
  void handle_mouseclick (int button, int state, int x, int y){
	  if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
		  if (nPoints == 2) nPoints = 0;

		  printf("%d (%d, %d) ==> (%f, %f)\n", nPoints, x, y, x_convert(x), y_convert(y));

		  x_coord[nPoints] = x_convert(x);
		  y_coord[nPoints] = y_convert(y);
		  nPoints++;
		  glutPostRedisplay();
	  }
  }
  int main(int argc, char** argv)
  {
	  glutInit(&argc, argv);
	  glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB |GLUT_DEPTH);
	  glutInitWindowSize (500, 500);
	  glutInitWindowPosition (100, 100);
	  glutCreateWindow ("hello");
	  init ();
	  glutDisplayFunc( display );
	  glutReshapeFunc(myReshape);
	  glutMouseFunc(handle_mouseclick);
	  glutMainLoop();
	  return 0;
  }

<2>Bezier曲線(三次:四點確定一條曲線)

 #include <windows.h>
 #include <gl/glut.h>
 #include <gl/gl.h>
 #include <stdio.h>
 #include <math.h>
 GLfloat x_coord[4], y_coord[4];
 int nPoints = 0;
 
 inline GLfloat x_convert (int x)
 {
  return -5.0+x/249.0*10;
 }
 
 inline GLfloat y_convert (int y)
 {
  return 5.0 - y/249.0*10;
 }
 
 void init(){
   glClearColor(1,1,1,0);
 
 }
 void myReshape(int w,int h)
 {
  glViewport(0,0,(GLsizei)w,(GLsizei)h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  //gluPerspective(45.0,(GLfloat)w/(GLfloat)h,1.0,50.0);
  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)h/(GLfloat)w,5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0,-5.0,5.0);
 
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
 }
 
 //P(t)= B0,3(t)P0 + B1,3(t)P1+ B2,3(t)P2﹢B3,3(t)P3
    //  B0,3(t)﹦(1-t)3
    // B1,3(t)﹦3t(1-t)2
     //B2,3(t)﹦3t2(1-t)
     //B3,3(t)﹦t3
 
 void Bezier(int n)  //Bezier曲線
 {
     float t, dt, t2, t3, f1, f2, f3, f4;
 
     dt = 1.0/n;      // t runs from 0 to 1.
 
     glBegin(GL_LINE_STRIP);
  for (t = 0.0; t <= 1.0; t += dt) {
         t2 = (1-t) *(1- t);
         t3 = t2 * (1-t);       // t3 =(1-t)*(1-t)*(1-t)
 
         f1 = t3;
         f2 = 3*t*t2;
         f3 = 3*t*t*(1-t);
         f4 = t*t*t;
 
         glVertex2f( f1*x_coord[0] + f2*x_coord[1] + f3*x_coord[2] + f4*x_coord[3],
                          f1*y_coord[0] + f2*y_coord[1] + f3*y_coord[2] + f4*y_coord[3]);
     }
     glEnd();
 }
 void display(){
     glClear(GL_COLOR_BUFFER_BIT);
 
         glColor3f (1, 0, 0);
    glBegin(GL_LINE_STRIP);
    for (int i = 0; i < nPoints; i++)
  glVertex3f (x_coord[i], y_coord[i], 0.0);
    glEnd();
 
         glColor3f (0, 1, 0);
     if (nPoints == 4)
  Bezier(20);
 
  glFlush();
 
 }
 
 void handle_mouseclick (int button, int state, int x, int y)
 {
  if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
  if (nPoints == 4) nPoints = 0;
 
  printf("%d (%d, %d) ==> (%f, %f)\n", nPoints, x, y, x_convert(x), y_convert(y));
 
  x_coord[nPoints] = x_convert(x);
  y_coord[nPoints] = y_convert(y);
  nPoints++;
  glutPostRedisplay();
  }
 }
 int  main(int argc, char** argv)
 {
    glutInit(&argc, argv);
    glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB |GLUT_DEPTH);
    glutInitWindowSize (250, 250);
    glutInitWindowPosition (100, 100);
    glutCreateWindow ("hello");
    init ();
 
    glutDisplayFunc( display );
     glutReshapeFunc(myReshape);
    glutMouseFunc(handle_mouseclick);
 
    glutMainLoop();
    return 0;
 }

<3>Hermit曲線(三次,三點確定一條曲線)

 #include <windows.h>
 #include <gl/glut.h>
 #include <gl/gl.h>
 #include <stdio.h>
 #include <math.h>
  GLfloat x_coord[3], y_coord[3];
  int nPoints = 0;
  inline GLfloat x_convert (int x)
  {
  return -8.0+x/499.0*16;
  }
  inline GLfloat y_convert (int y)
  {
  return 8.0 - y/499.0*16;
  }
  void init(){
    glClearColor(1,1,1,0);
  }
  void myReshape(int w,int h)
  {
  glViewport(0,0,(GLsizei)w,(GLsizei)h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  //gluPerspective(45.0,(GLfloat)w/(GLfloat)h,1.0,50.0);
  if(w<=h)
  glOrtho(-8.0,8.0,-8.0*(GLfloat)h/(GLfloat)w,8.0*(GLfloat)h/(GLfloat)w,-8.0,8.0);
  else
  glOrtho(-8.0*(GLfloat)h/(GLfloat)w,8.0*(GLfloat)h/(GLfloat)w,-8.0,8.0,-8.0,8.0);
 
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  }
 
  void Hermit(int n)  //
  {
    float t, dt, t2, t3, f1, f2, f3, f4;
 
     dt = 1.0/n;      // t runs from 0 to 1.
     GLfloat PT0_x = x_coord[1] - x_coord[0];
     GLfloat PT0_y = y_coord[1] - y_coord[0];
     GLfloat PT1_x = x_coord[2] - x_coord[1];
  GLfloat PT1_y = y_coord[2] - y_coord[1];
     glBegin(GL_LINE_STRIP);
  for (t = 0.0; t <= 1.0; t += dt) {
         t2 = t * t;
         t3 = t2 * t;       // t3 = t * t * t
         f1 = 2.0*t3 - 3.0*t2 + 1.0;
         f2 = -2.0*t3 + 3.0*t2;
         f3 = t3 - 2.0*t2 + t;
         f4 = t3 - t2;
         glVertex2f( f1*x_coord[0] + f2*x_coord[2] + f3*PT0_x + f4*PT1_x,
                          f1*y_coord[0] + f2*y_coord[2] + f3*PT0_y + f4*PT1_y );
     }
     glEnd();
  }
  void display(){
      glClear(GL_COLOR_BUFFER_BIT);
 
         glColor3f(0,1,0);                //畫兩點之間的直線
    glBegin(GL_LINE_STRIP);
    for (int i = 0; i < nPoints; i++)
  glVertex3f (x_coord[i], y_coord[i], 0.0);
    glEnd();
 
        glColor3f (1.0, 0, 0);            //調用DDA畫線算法
     if (nPoints == 3)
  Hermit(20);
 
  glFlush();
 
  }
  void handle_mouseclick (int button, int state, int x, int y){
  if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
  if (nPoints == 3) nPoints = 0;
 
  printf("%d (%d, %d) ==> (%f, %f)\n", nPoints, x, y, x_convert(x), y_convert(y));
 
  x_coord[nPoints] = x_convert(x);
  y_coord[nPoints] = y_convert(y);
  nPoints++;
  glutPostRedisplay();
  }
  }
 int main(int argc, char** argv)
  {
     glutInit(&argc, argv);
     glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB |GLUT_DEPTH);
     glutInitWindowSize (500, 500);
     glutInitWindowPosition (100, 100);
     glutCreateWindow ("hello");
     init ();
     glutDisplayFunc( display );
      glutReshapeFunc(myReshape);
     glutMouseFunc(handle_mouseclick);
     glutMainLoop();
     return 0;
  }

<4>B樣條曲線(實現鼠標右鍵在屏幕中選點,左鍵可拖動點)(三次,四點確定一條曲線)


#include <windows.h> #include <stdio.h> #include <math.h>

#include <gl/glut.h> #pragma comment(lib,"glut32.lib")

GLfloat x_coord[100], y_coord[100];

int nPoints = 0;

int j=0;

inline GLfloat x_convert (int x) { return -5.0+x/249.0*10; }

inline GLfloat y_convert (int y) { return 5.0 - y/249.0*10; }

void init(){ glClearColor(1,1,1,0);

} void myReshape(int w,int h) { glViewport(0,0,(GLsizei)w,(GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); //gluPerspective(45.0,(GLfloat)w/(GLfloat)h,1.0,50.0); 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)h/(GLfloat)w,5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0,-5.0,5.0);

glMatrixMode(GL_MODELVIEW); glLoadIdentity(); }

// (1/2)*(t-1)*(t-1) // (1/2)*(-2*t*t+2*t+1) // (1/2)*t*t

void B2(int n) //B樣條3次曲線 { float t, dt, t2, t3, f1, f2, f3, f4;

dt = 1.0/n; // t runs from 0 to 1.

glBegin(GL_LINE_STRIP);

for(int j=0; j< (nPoints - 2 ); j++ ) for (t = 0.0; t <= 1.0; t += dt) {

f1 = (1.0/6)*((-1)*t*t*t+3*t*t-3*t+1); f2 = (1.0/6)*(3*t*t*t-6*t*t+4); f3 = (1.0/6)*((-3)*t*t*t+3*t*t +3*t +1); f4= (1.0/6)*(t*t*t);

glVertex2f( f1*x_coord[j] + f2*x_coord[j+1] + f3*x_coord[j+2]+ f4*x_coord[j+3], f1*y_coord[j] + f2*y_coord[j+1] + f3*y_coord[j+2] + f4*y_coord[j+3]); } glEnd(); }

void display(){ glClear(GL_COLOR_BUFFER_BIT);

glBegin(GL_LINE_STRIP); glColor3f (0, 1, 0); for (int i = 0; i < nPoints; i++) { glVertex3f (x_coord[i], y_coord[i], 0.0); } glEnd();

glColor3f (1.0, 0, 0); if (nPoints >=4) { B2(20); } glFlush();

}

void handle_mouseclick (int button, int state, int x, int y) { if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {

if( nPoints >=4 ) j++;

printf("%d (%d, %d) ==> (%f, %f)\n", nPoints, x, y, x_convert(x), y_convert(y));

x_coord[nPoints] = x_convert(x); y_coord[nPoints] = y_convert(y);

nPoints++;

glutPostRedisplay(); } }

void mousemotion(int x, int y) { float min =99999999; int index; x = x_convert(x); y = y_convert(y); int i ; for(i=0; i <min; i++) { if(min > (x-x_coord[i])*(x-x_coord[i]) + (y-y_coord[i])*(y-y_coord[i]) ){ min=(x-x_coord[i])*(x-x_coord[i]) + (y-y_coord[i])*(y-y_coord[i]) ; index=i; } x_coord[index] = x; y_coord[index] = y; } glutPostRedisplay(); }

int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB |GLUT_DEPTH); glutInitWindowSize (250, 250); glutInitWindowPosition (100, 100); glutCreateWindow ("hello"); init ();

glutDisplayFunc( display ); glutReshapeFunc(myReshape); glutMouseFunc(handle_mouseclick); glutMotionFunc(mousemotion);

glutMainLoop(); return 0; }

再分享一下我老師大神的人工智能教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智能的隊伍中來!https://blog.csdn.net/jiangjunshow

OpenGL 繪制B樣條曲線