OpenGL进阶(二)样条曲线的绘制

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)

代码实现:

[cpp]  view plain copy
  1. void getInterpolation(point &p1,point &p2,point &p3,point &p4,float s,float u,point *result)  
  2. {  
  3.     float u2=u*u;  
  4.     float u3=u2*u;  
  5.     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);  
  6.     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);  
  7. }  
  8. void drawCdnLine(point *a,float tension)  
  9. {  
  10.     int i,j,k=100;  
  11.     float s,step=1.0/(float)k;  
  12.     s=(1.0-tension)/2.0;  
  13.     glColor3f(1.0f,0.0f,0.0f);  
  14.     glBegin(GL_LINE_STRIP);  
  15.     float uValue;  
  16.     for(i=0;i<4;i++)  
  17.     {  
  18.         uValue=0.0f;  
  19.         for(j=0;j<k;j++)  
  20.         {  
  21.         point tmp;  
  22.         getInterpolation(a[i],a[(i+1)%4],a[(i+2)%4],a[(i+3)%4],s,uValue,&tmp);  
  23.         glVertex2f(tmp.x,tmp.y);  
  24.         uValue += step;  
  25.         }  
  26.     }  
  27.     glEnd();  
  28. }  
  29. void renderGL()  
  30. {  
  31.     // Clear the color and depth buffers.  
  32.     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );  
  33.     // We don't want to modify the projection matrix. */  
  34.     glMatrixMode( GL_MODELVIEW );  
  35.     glLoadIdentity( );  
  36.     // Move down the z-axis.  
  37.     glTranslatef( 0.0, -1.0, -8.0 );  
  38.     point c[4]={{-2,0,0},{0,2,0},{3,0,0},{0,-1,0}};  
  39.     drawCdnLine(c,0.0);  
  40.     SDL_GL_SwapBuffers( );  
  41. }  



Bezier曲线

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

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

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

[cpp]  view plain copy
  1. GLfloat c[4][3]={{-10,-10,0},{-1,20,0},{1,-20,0},{10,10,0}};  


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

[cpp]  view plain copy
  1. glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &c[0][0]);  
  2. glEnable(GL_MAP1_VERTEX_3);  


然后写渲染函数:

[cpp]  view plain copy
  1. void renderGL()  
  2. {  
  3.     int i;  
  4.     // Clear the color and depth buffers.  
  5.     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );  
  6.     // We don't want to modify the projection matrix. */  
  7.     glMatrixMode( GL_MODELVIEW );  
  8.     glLoadIdentity( );  
  9.     // Move down the z-axis.  
  10.     glTranslatef( 0.0, -0.0, -50.0 );  
  11.     glColor3f(1.0, 1.0, 1.0);  
  12.     glBegin(GL_POINTS);  
  13.     for (i = 0; i <= 90; i++)  
  14.          glEvalCoord1f((GLfloat) i/90.0);  
  15.     glEnd();  
  16.     glPointSize(5.0);  
  17.     glColor3f(1.0, 1.0, 0.0);  
  18.     glBegin(GL_POINTS);  
  19.       for (i = 0; i < 4; i++)  
  20.          glVertex3fv(&c[i][0]);  
  21.     glEnd();  
  22.     SDL_GL_SwapBuffers( );  
  23. }  



主要注意两个函数: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()函数将其关闭。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值