阅读:1344回复:0
OpenGL系列讲座(19)
3.3 曲线生成
计算机图形学中,所有的光滑曲线都采用线段逼近来模拟,而且许多有用的曲线在数学 上只用少数几个参数(如控制点等)来描述。本节简要地介绍一下OpenGL中Bezier曲线的 绘制方法。 3.3.1 曲线绘制举例 下面我们来看一个简单的例子,这是用四个控制顶点来画一条三次Bezier曲线。程序如 下 bzcurve.c : 例 3-8 Bezier曲线绘制例程 bzcurve.c #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void myinit(void); void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void); GLfloat ctrlpoints[4][3] = { { -4.0, -4.0, 0.0}, { -2.0, 4.0, 0.0}, {2.0, -4.0, 0.0}, {4.0, 4.0, 0.0}}; void myinit(void) { glClearColor(0.0, 0.0, 0.0, 1.0); glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]); glEnable(GL_MAP1_VERTEX_3); glShadeModel(GL_FLAT); } void CALLBACK display(void) { int i; glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); glBegin(GL_LINE_STRIP); for (i = 0; i <= 30; i++) glEvalCoord1f((GLfloat) i/30.0); glEnd(); /* 显示控制点 */ glPointSize(5.0); glColor3f(1.0, 1.0, 0.0); glBegin(GL_POINTS); for (i = 0; i < 4; i++) glVertex3fv(&ctrlpoints[0]); glEnd(); glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); 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)w/(GLfloat)h, 5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void main(void ) { auxInitDisplayMode (AUX_SINGLE | AUX_RGBA); auxInitPosition (0, 0, 500, 500); auxInitWindow ("Bezier Curves"); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); } 图 3-3-7 一条光滑的Bezier曲线 3.3.2 曲线定义和启动 OpenGL中曲线定义的函数为: void glMap1{fd}(GLenum target,TYPE u1,TYPE u2,GLint stride, GLint order,const TYPE *points); 函数的第一个参数target指出控制顶点的意义以及在参数points中需要提供多少值, 具体值见表3-3-1所示。参数points指针可以指向控制点集、RGBA颜色值或纹理坐标串等。 例如若target是GL_MAP1_COLOR_4,则就能在RGBA四维空间中生成一条带有颜色信息的曲 线,这在数据场可视化中应用极广。参数u1和u2,指明变量U的范围,U一般从0变化到1。 参数stride是跨度,表示在每块存储区内浮点数或双精度数的个数,即两个控制点间的偏移 量,比如上例中的控制点集ctrpoint[4][3]的跨度就为3,即单个控制点的坐标元素个数。 函数参数order是次数加1,叫阶数,与控制点数一致。 ________________________________________________________________________ 参 数 意 义 ________________________________________________________________________ GL_MAP1_VERTEX_3 x,y,z 顶点坐标 GL_MAP1_VERTEX_4 x,y,z,w 顶点坐标 GL_MAP1_INDEX 颜色表 GL_MAP1_COLOR_4 R,G,B,A GL_MAP1_NORMAL 法向量 GL_MAP1_TEXTURE_COORD_1 s 纹理坐标 GL_MAP1_TEXTURE_COORD_2 s,t 纹理坐标 GL_MAP1_TEXTURE_COORD_3 s,t,r 纹理坐标 GL_MAP1_TEXTURE_COORD_4 s,t,r,q 纹理坐标 ________________________________________________________________________ 表3-3-1 用于glMap1*()控制点的数据类型 曲线定义后,必须要启动,才能进行下一步的绘制工作。启动函数仍是glEnable(),其 中参数与glMap1*()的第一个参数一致。同样,关闭函数为glDisable(),参数也一样。 3.3.3 曲线坐标计算 这里提到的坐标概念是广义的,与以前定义的有点不同,具体地说就是表3-3-1所对应的 类型值。OpenGL曲线坐标计算的函数形式如下: void glEvalCoord1{fd}[v](TYPE u); 产生曲线坐标值并绘制。参数u是定义域内的值,这个函数调用一次只产生一个坐标。 3.3.4 定义均匀间隔曲线坐标值 在使用glEvalCoord1*()计算坐标,因为u可取定义域内的任意值,所以由此计算出的 坐标值也是任意的。但是,目前用得最普遍的仍是取等间隔值。要获得等间隔值,OpenGL提 供了两个函数,即先调用glMapGrid1*()定义一个一维网格,然后用glEvalMesh1()计算响应 的坐标值。 下面详细解释这两个函数: void glMapGrid1{fd}(GLint n,TYPE u1,TYPE u2); 定义一个网格,从u1到u2分为n步,它们是等间隔的。实际上,这个函数定义的是参 数空间网格。 void glEvalMesh1(GLenum mode,GLint p1,GLint p2); 计算并绘制坐标点。参数mode可以是GL_POINT或GL_LINE,即沿曲线绘制点或沿曲线 绘制相连的线段。这个函数的调用效果同在p1和p2之间的每一步给出一个glEvalCoord1() 的效果一样。从编程角度来说,除了当i=0或i=n,它准确以u1或u2作为参数调用glEvalCoord1() 之外,它等价于一下代码: glBegin(GL_POINT); /* glBegin(GL_LINE_STRIP); */ for(i=p1;i<=p2;i++) glEvalCoord1(u1+i*(u2-u1)/n); glEnd(); |
|
|