阅读:1563回复:0
OpenGL系列讲座(20)
3.4 曲面构造
同样,计算机图形学中的所有光滑曲面也都采用多边形逼近来绘制,而且许多有用的曲 面在数学上也只用少数几个参数(如控制点或网等)来描述。通常,若用16个控制点描述一 个曲面,要比用1000多个三角形和每个顶点的法向信息要节省很多内存。而且,1000个三 角形仅仅只逼近曲面,而控制点可以精确地描述实际曲面,且可自动计算法向。本节简要地 介绍一下OpenGL中Bezier曲面的绘制方法,所有相关的函数都与曲线的情况类似,只是二 维空间而已。 3.4.1 曲面定义和坐标计算 曲面定义函数为: void glMap2{fd}(GLenum target,TYPE u1,TYPE u2,GLint ustride,GLint uorder, TYPE v1,TYPE v2,GLint vstride,GLint vorder,TYPE points); 参数target可以是表3-3-1中任意值,不过需将MAP1改为MAP2。同样,启动曲面的函 数仍是glEnable(),关闭是glDisable()。u1、u2为u的最大值和最小值;v1、v2为v的最 大值和最小值。参数ustride和vstride指出在控制点数组中u和v向相邻点的跨度,即可 从一个非常大的数组中选择一块控制点长方形。例如,若数据定义成如下形式: GLfloat ctlpoints[100][100][3]; 并且,要用从ctlpoints[20][30]开始的4x4子集,选择ustride为100*3,vstride为3, 初始点设置为ctlpoints[20][30][0]。最后的参数都是阶数,uorder和vorder,二者可以 不同。 曲面坐标计算函数为: void glEvalCoord2{fd}[v](TYPE u,TYPE v); 产生曲面坐标并绘制。参数u和v是定义域内的值。 下面看一个绘制Bezier曲面的例子 bzwiresf.c: 例 3-9 Bezier网状曲面绘制例程 bzwiresf.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][4][3] = { {{-1.5, -1.5, 2.0}, {-0.5, -1.5, 2.0}, {0.5, -1.5, -1.0}, {1.5, -1.5, 2.0}}, {{-1.5, -0.5, 1.0}, {-0.5, 1.5, 2.0}, {0.5, 0.5, 1.0}, {1.5, -0.5, -1.0}}, {{-1.5, 0.5, 2.0}, {-0.5, 0.5, 1.0}, {0.5, 0.5, 3.0}, {1.5, -1.5, 1.5}}, {{-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0}, {0.5, 0.5, 1.0}, {1.5, 1.5, -1.0}} }; void myinit(void) { glClearColor (0.0, 0.0, 0.0, 1.0); glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &ctrlpoints[0][0][0]); glEnable(GL_MAP2_VERTEX_3); glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0); glEnable(GL_DEPTH_TEST); } void CALLBACK display(void) { int i, j; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(0.3, 0.6, 0.9); glPushMatrix (); glRotatef(35.0, 1.0, 1.0, 1.0); for (j = 0; j <= 8; j++) { glBegin(GL_LINE_STRIP); for (i = 0; i <= 30; i++) glEvalCoord2f((GLfloat)i/30.0, (GLfloat)j/8.0); glEnd(); glBegin(GL_LINE_STRIP); for (i = 0; i <= 30; i++) glEvalCoord2f((GLfloat)j/8.0, (GLfloat)i/30.0); glEnd(); } glPopMatrix (); glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-4.0, 4.0, -4.0*(GLfloat)h/(GLfloat)w, 4.0*(GLfloat)h/(GLfloat)w, -4.0, 4.0); else glOrtho(-4.0*(GLfloat)w/(GLfloat)h, 4.0*(GLfloat)w/(GLfloat)h, -4.0, 4.0, -4.0, 4.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void main(void) { auxInitDisplayMode (AUX_SINGLE | AUX_RGBA); auxInitPosition (0, 0, 500, 500); auxInitWindow ("Wireframe Bezier Surface"); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); } 以上程序运行结果是一个网状的曲面。 图 3-3-8 Bezier网状曲面 3.4.2 定义均匀间隔的曲面坐标值 OpenGL中定义均匀间隔的曲面坐标值的函数与曲线的类似,其函数形式为: void glMapGrid2{fd}(GLenum nu,TYPE u1,TYPE u2, GLenum nv,TYPE v1,TYPE v2); void glEvalMesh2(GLenum mode,GLint p1,GLint p2,GLint q1,GLint q2); 第一个函数定义参数空间的均匀网格,从u1到u2分为等间隔的nu步,从v1到v2分为 等间隔的nv步,然后glEvalMesh2()把这个网格应用到已经启动的曲面计算上。第二个函数 参数mode除了可以是GL_POINT和GL_LINE外,还可以是GL_FILL,即生成填充空间曲面。 下面举出一个用网格绘制一个经过光照和明暗处理的Bezier曲面的例程 bzmesh.c: 例 3-10 加光照的均匀格网Bezier曲面绘制例程 bzmesh.c #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void myinit(void); void initlights(void); void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void); /* 控制点坐标 */ GLfloat ctrlpoints[4][4][3] = { {{-1.5, -1.5, 2.0}, {-0.5, -1.5, 2.0}, {0.5, -1.5, -1.0}, {1.5, -1.5, 2.0}}, {{-1.5, -0.5, 1.0}, {-0.5, 1.5, 2.0}, {0.5, 0.5, 1.0}, {1.5, -0.5, -1.0}}, {{-1.5, 0.5, 2.0}, {-0.5, 0.5, 1.0}, {0.5, 0.5, 3.0}, {1.5, -1.5, 1.5}}, {{-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0}, {0.5, 0.5, 1.0}, {1.5, 1.5, -1.0}} }; void initlights(void) { GLfloat ambient[] = { 0.4, 0.6, 0.2, 1.0 }; GLfloat position[] = { 0.0, 1.0, 3.0, 1.0 }; GLfloat mat_diffuse[] = { 0.2, 0.4, 0.8, 1.0 }; GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat_shininess[] = { 80.0 }; glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_POSITION, position); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); } void CALLBACK display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glRotatef(35.0, 1.0, 1.0, 1.0); glEvalMesh2(GL_FILL, 0, 20, 0, 20); glPopMatrix(); glFlush(); } void myinit(void) { glClearColor (0.0, 0.0, 0.0, 1.0); glEnable (GL_DEPTH_TEST); glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &ctrlpoints[0][0][0]); glEnable(GL_MAP2_VERTEX_3); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0); initlights(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-4.0, 4.0, -4.0*(GLfloat)h/(GLfloat)w, 4.0*(GLfloat)h/(GLfloat)w, -4.0, 4.0); else glOrtho(-4.0*(GLfloat)w/(GLfloat)h, 4.0*(GLfloat)w/(GLfloat)h, -4.0, 4.0, -4.0, 4.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void main(void) { auxInitDisplayMode (AUX_SINGLE | AUX_RGBA); auxInitPosition (0, 0, 500, 500); auxInitWindow ("Lighted and Filled Bezier Surface"); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); } 以上程序运行结果是一个加上光影的曲面。 图 3-3-9 带光影的曲面 3.4.3 纹理曲面 在本篇的第二章中已经讲过纹理的用法,这一节将结合曲面的生成试试纹理的应用。下 面我们先看一个例子 texsurf.c: 例 3-11 纹理曲面例程绘制 texsurf.c #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> #include <math.h> void myinit(void); void makeImage(void); void CALLBACK display(void); void CALLBACK myReshape(GLsizei w, GLsizei h); GLfloat ctrlpoints[4][4][3] = { {{-1.5, -1.5, 2.0}, {-0.5, -1.5, 2.0}, {0.5, -1.5, -1.0}, {1.5, -1.5, 2.0}}, {{-1.5, -0.5, 1.0}, {-0.5, 1.5, 2.0}, {0.5, 0.5, 1.0}, {1.5, -0.5, -1.0}}, {{-1.5, 0.5, 2.0}, {-0.5, 0.5, 1.0}, {0.5, 0.5, 3.0}, {1.5, -1.5, 1.5}}, {{-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0}, {0.5, 0.5, 1.0}, {1.5, 1.5, -1.0}} }; GLfloat texpts[2][2][2] = {{{0.0, 0.0}, {0.0, 1.0}}, {{1.0, 0.0}, {1.0, 1.0}}}; void CALLBACK display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); glEvalMesh2(GL_FILL, 0, 20, 0, 20); glFlush(); } #define imageWidth 64 #define imageHeight 64 GLubyte image[3*imageWidth*imageHeight]; void makeImage(void) { int i, j; float ti, tj; for (i = 0; i < imageWidth; i++) { ti = 2.0*3.14159265*i/imageWidth; for (j = 0; j < imageHeight; j++) { tj = 2.0*3.14159265*j/imageHeight; image[3*(imageHeight*i+j)] = (GLubyte) 127*(1.0+sin(ti)); image[3*(imageHeight*i+j)+1] = (GLubyte) 127*(1.0+cos(2*tj)); image[3*(imageHeight*i+j)+2] = (GLubyte) 127*(1.0+cos(ti+tj)); } } } void myinit(void) { glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &ctrlpoints[0][0][0]); glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2, &texpts[0][0][0]); glEnable(GL_MAP2_TEXTURE_COORD_2); glEnable(GL_MAP2_VERTEX_3); glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0); makeImage(); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, 3, imageWidth, imageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, image); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glEnable(GL_NORMALIZE); glShadeModel (GL_FLAT); } void CALLBACK myReshape(GLsizei w, GLsizei h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-4.0, 4.0, -4.0*(GLfloat)h/(GLfloat)w, 4.0*(GLfloat)h/(GLfloat)w, -4.0, 4.0); else glOrtho(-4.0*(GLfloat)w/(GLfloat)h, 4.0*(GLfloat)w/(GLfloat)h, -4.0, 4.0, -4.0, 4.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef(35.0, 1.0, 1.0, 1.0); } void main(void) { auxInitDisplayMode (AUX_SINGLE | AUX_RGBA); auxInitPosition (0, 0, 500, 400); auxInitWindow ("Texture Surface"); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); } 以上程序运行结果是一个带纹理的曲面。 图 3-3-10 带纹理的曲面 3.4.4 NURBS曲面 OpenGL的功能库提供了一系列NURBS曲面(非均匀有理B样条曲面)的函数。本节不具 体讲各函数的用法,仅举出一个应用例子,其余的读者可以参考手册。例程nurbsurf.c如下: 例 3-12 NURBS曲面绘制例程 nurbsurf.c #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void myinit(void); void init_surface(void); void CALLBACK display(void); void CALLBACK myReshape(GLsizei w, GLsizei h); GLfloat ctlpoints[4][4][3]; GLUnurbsObj *theNurb; /* 初始化控制点坐标,x,y,z范围从-3到3 */ void init_surface(void) { int u, v; for (u = 0; u < 4; u++) { for (v = 0; v < 4; v++) { ctlpoints[v][0] = 2.0*((GLfloat)u - 1.5); ctlpoints[v][1] = 2.0*((GLfloat)v - 1.5); if ( (u == 1 || u == 2) && (v == 1 || v == 2)) ctlpoints[v][2] = 3.0; else ctlpoints[v][2] = -3.0; } } } /* 定义曲面材质 (金色) */ void myinit(void) { GLfloat mat_diffuse[] = { 0.88, 0.66, 0.22, 1.0 }; GLfloat mat_specular[] = { 0.92, 0.9, 0.0, 1.0 }; GLfloat mat_shininess[] = { 80.0 }; glClearColor (0.0, 0.0, 0.0, 1.0); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); init_surface(); theNurb = gluNewNurbsRenderer(); gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0); gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL); } void CALLBACK display(void) { GLfloat knots[8] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0}; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glRotatef(330.0, 1.,0.,0.); glScalef (0.5, 0.5, 0.5); gluBeginSurface(theNurb); gluNurbsSurface(theNurb, 8, knots, 8, knots, 4 * 3, 3, &ctlpoints[0][0][0], 4, 4, GL_MAP2_VERTEX_3); gluEndSurface(theNurb); glPopMatrix(); glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective (45.0, (GLdouble)w/(GLdouble)h, 3.0, 8.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef (0.0, 1.0, -5.0); } void main(void) { auxInitDisplayMode (AUX_SINGLE | AUX_RGBA); auxInitPosition (0, 0, 500, 500); auxInitWindow ("NURBS Surface"); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); } 以上程序运行结果是一个金色的NURBS曲面。 图 3-3-11 Nurbs曲面 |
|
|