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()函数将其关闭。