Cardinal样条曲线

这个比较简单,一个终点,一个起点,两个控制点。

终点和起点中间的点靠插值实现,插值函数:

P(u)=Pk-1(-s*u*u*u+2s*u*u)+Pk[(2-s)u*u*u+(s-3)u*u+1]+Pk+1[(s-2)*u*u*u+(3-2s)*u*u+s*u]+Pk+2(s*u*u*u-s*u*u)

代码实现:

void getInterpolation(point &p1,point &p2,point &p3,point &p4,float s,float u,point *result) {     float u2=u*u;     float u3=u2*u;     result->x=p1.x*(2*s*u2 - s*u3 - s*u) + p2.x*((2-s)*u3 + (s-3)*u2 + 1) +p3.x*((s-2)*u3 + (3-2*s)*u2 + s*u) + p4.x*(s*u3 - s*u2);     result->y=p1.y*(2*s*u2 - s*u3 - s*u) + p2.y*((2-s)*u3 + (s-3)*u2 + 1) +p3.y*((s-2)*u3 + (3-2*s)*u2 + s*u) + p4.y*(s*u3 - s*u2); } void drawCdnLine(point *a,float tension) {     int i,j,k=100;     float s,step=1.0/(float)k;     s=(1.0-tension)/2.0;     glColor3f(1.0f,0.0f,0.0f);     glBegin(GL_LINE_STRIP);     float uValue;     for(i=0;i<4;i++)     {         uValue=0.0f;         for(j=0;j<k;j++)         {         point tmp;         getInterpolation(a[i],a[(i+1)%4],a[(i+2)%4],a[(i+3)%4],s,uValue,&tmp);         glVertex2f(tmp.x,tmp.y);         uValue += step;         }     }     glEnd(); } void renderGL() {     // Clear the color and depth buffers.     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );     // We don't want to modify the projection matrix. */     glMatrixMode( GL_MODELVIEW );     glLoadIdentity( );     // Move down the z-axis.     glTranslatef( 0.0, -1.0, -8.0 );     point c[4]={{-2,0,0},{0,2,0},{3,0,0},{0,-1,0}};     drawCdnLine(c,0.0);     SDL_GL_SwapBuffers( ); }



Bezier曲线

与上面的类似,只是插值的方式不同。

这里就直接调用OpenGL的库函数了。

首先定义一个全局的数组:

GLfloat c[4][3]={{-10,-10,0},{-1,20,0},{1,-20,0},{10,10,0}};


初始化函数中添加两行代码:

glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &c[0][0]); glEnable(GL_MAP1_VERTEX_3);


然后写渲染函数:

void renderGL() {     int i;     // Clear the color and depth buffers.     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );     // We don't want to modify the projection matrix. */     glMatrixMode( GL_MODELVIEW );     glLoadIdentity( );     // Move down the z-axis.     glTranslatef( 0.0, -0.0, -50.0 );     glColor3f(1.0, 1.0, 1.0);     glBegin(GL_POINTS);     for (i = 0; i <= 90; i++)          glEvalCoord1f((GLfloat) i/90.0);     glEnd();     glPointSize(5.0);     glColor3f(1.0, 1.0, 0.0);     glBegin(GL_POINTS);       for (i = 0; i < 4; i++)          glVertex3fv(&c[i][0]);     glEnd();     SDL_GL_SwapBuffers( ); }



主要注意两个函数:glMap1和glEvalCoord1。

1.void glMap1{fd}(GLenum target,TYPE u1,TYPE u2,GLint stride, GLint order,const TYPE *points);
功能:定义求值器。 

参数:target:指出了控制顶点的意义以及在points参数中需要提供多少值。

points:可以指向控制点集、RGBA颜色值或是纹理坐标串等。

u1、u2:限定了变量U的取值范围,通常是从0变化到1。

stride:表示跨度(在每块存储区内浮点数或双精度数的个数,即两个控制点间的偏移量)。

order:阶数,等于次数加1,与控制点数相等。

2.void glEvalCoord1{fd}[v](TYPE u)。
功能:该函数将产生曲线坐标值并将其绘制。

参数:u:为定义域内的任意值,每调用一次将只产生一个坐标,此坐标值也是任意的。

但目前较多采用的是定义均匀间隔曲线坐标值,依次调用glMapGrid1*()和glEvalMesh1()可以获得等间隔值。这两个函数分别用来定义一个一维网格和计算相应的坐标值。

另外,曲线定义后必须再glEnable()函数显式启动后才能起作用,其参数与target保持一致。在使用完毕后通过glDisable()函数将其关闭。