我要发帖 回复

新手上路

1

主题

10

积分

0

专家分

:

私信
发表时间 : 2007-11-28 16:05:24 | 浏览 : 2835    评论 : 2
计算机图形学中的所有光滑曲面也都采用多边形逼近来绘制,而且许多有用的曲

面在数学上也只用少数几个参数(如控制点或网等)来描述。通常,若用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曲面

评分

参与人数 1积分 +10 收起 理由
tan_dunming + 10

查看全部评分

最近VR访客

tan_dunming 评论于2007-11-28 16:21:18
不错,OpenGL曲线曲面非常有用,而且是硬件支持的,绘制起来效率非常高,很值得研究。
但是真正要理解期中一些参数的意义最好还是找一本专业方面的书籍学一学。

楼主的帖子很全面,但大家最好也研究研究NURBS曲面如何贴纹理,红宝书里没有介绍,其实很简单,论坛里有帖子。
http://www.52vr.com/bbs/viewthread.php?tid=4443
追求卓越
adafird 评论于2013-1-10 11:20:12
楼主能简要介绍一下利用Creator制作曲面的方法或经验吗?

手机版|VR开发网 统计 津ICP备18009691号
网安备12019202000257

GMT+8, 2021-9-29 10:19 AM

返回顶部