发信人: yxy (田丝丝#冬眠的小肥鹰), 信区: GAME_Designer 
标  题: OPENGL(14) 
发信站: BBS 水木清华站 (Tue Feb 17 16:24:53 1998) 
 
曲面的构造可以是网格线和填充曲面形式,其实与曲线很类似只是变为 
二维而已。 
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的定义同上次介绍的曲线中target的定义。 
U V是二维曲面坐标 
uorder,vorder;ustride,vstride的定义都类似曲线定义。 
points是控制点坐标 
 
2.曲面任意一点的计算 
void glEvalCoord2{fd}[v](TYPE u,TYPE v); 
以曲线坐标U V来计算曲面内任意一点的世界坐标的位置 
 
3.曲面绘制的控制 
void glMapGrid2{fd}(GLenum nu,TYPE u1,TYPE u2,GLenum nv,TYPE v1,TYPE v2); 
定义曲面参数空间均匀网格,从u1到u2分为等间隔nu步,从v1到v2分为等间隔nv步。 
 
下面给出一个以网格线描绘曲面的例子: 
//////////////////////////////////////////////////////////// 
//sample.cpp 
#include "glos.h" 
#include <GL/gl.h> 
#include <GL/glaux.h> 
#include "windows.h" 
void myinit(void); 
void CALLBACK  display(void); 
void CALLBACK  reshape(GLsizei w,GLsizei h); 
 
//控制点坐标 
GLfloat points[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 color[4][3]={ 
        {1.0,0.0,0.0},{0.0,1.0,0.0},{0.0,0.0,1.0},{1.0,1.0,1.0}}; 
 
void myinit(void) 

 
        auxInitDisplayMode(AUX_SINGLE|AUX_RGBA); 
        auxInitPosition(0,0,500,500); 
        auxInitWindow("sample1"); 
        glClearColor(0.0,0.0,0.0,0.0); 
        glClear(GL_COLOR_BUFFER_BIT); 
 
//利用glEnable()来启用曲面模式 
        glMap2f(GL_MAP2_VERTEX_3,0,1,3,4,0,1,12,4,&points[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 reshape(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)h/(GLfloat)w, 
         5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0,-5.0,5.0); 
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity(); 

 
 
void CALLBACK display(void) 

  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 
  glColor3f(0.0,0.0,1.0); 
  glPushMatrix(); 
  glRotatef(35.0,1.0,1.0,1.0); 
//用直线段的连接描绘曲面结构 
  glBegin(GL_LINE_STRIP); 
  int i,j; 
//在U V方向各画出8条网格线,用以构造曲面结构 
  for(j=0;j<=8;j++) 
  { 
         //在U方向用30条直线段描绘一条曲线 
          glBegin(GL_LINE_STRIP); 
           for(i=0;i<=30;i++) 
            glEvalCoord2f((GLfloat)i/30.0,(GLfloat)j/8.0); 
          glEnd(); 
          
        //在V方向用30条直线段描绘一条曲线 
          glBegin(GL_LINE_STRIP); 
           for(i=0;i<=30;i++) 
                   glEvalCoord2f((GLfloat)j/8.0,(GLfloat)i/30.0); 
          glEnd(); 
 } 
 
//用不同的颜色把控制点显示出来 
  glPointSize(4.0); 
  glBegin(GL_POINTS); 
  for(i=0;i<4;i++) 
  for(j=0;j<4;j++) 
  { 
      glColor3fv(color[i]); 
      glVertex3fv(&points[i][j][0]); 
  } 
  glEnd(); 
 
  glPopMatrix(); 
  glFlush(); 

void main(void) 

    myinit(); 
     
    auxReshapeFunc(reshape); 
    auxMainLoop(display); 

//end of sample 
/////////////////////////////////////////////////////// 
 
应用中常常不满足曲面的框架结构。下面就介绍填充曲面的绘制方法: 
 
void glEvalMesh2(GLenum mode,GLint p1,GLint p2,GLint q1,GLint q2); 
把用glMapGrid2{fd}()设置的网格应用到已经启用的曲面计算上。 
mode可以是GL_POINT GL_LINE GL_FILL。顾名思义,GL_FILL就是生成填充曲面 
 
这里给出一个有光照处理的BEZIER曲面的例子(这个曲面除了绘制方法不同,数学 
形式和前面的是一样的)。 
/////////////////////////////////////////////////////// 
//sample.cpp 
#include "glos.h" 
#include <GL/gl.h> 
#include <GL/glaux.h> 
#include "windows.h" 
void myinit(void); 
void CALLBACK  display(void); 
void CALLBACK  reshape(GLsizei w,GLsizei h); 
 
GLfloat points[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 color[4][3]={ 
        {1.0,0.0,0.0},{0.0,1.0,0.0},{0.0,0.0,1.0},{1.0,1.0,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 myinit(void) 

 
        auxInitDisplayMode(AUX_SINGLE|AUX_RGBA); 
        auxInitPosition(0,0,500,500); 
        auxInitWindow("sample1"); 
        glClearColor(0.0,0.0,0.0,0.0); 
        glClear(GL_COLOR_BUFFER_BIT); 
 
        glMap2f(GL_MAP2_VERTEX_3,0,1,3,4,0,1,12,4,&points[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); 
 
        glEnable(GL_DEPTH_TEST); 
//初始化光照、材质 
        initlights(); 
//      glShadeModel(GL_FLAT); 

 
void CALLBACK reshape(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)h/(GLfloat)w, 
         5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0,-5.0,5.0); 
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity(); 

 
 
void CALLBACK display(void) 

  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 
  glColor3f(0.0,0.0,1.0); 
  glPushMatrix(); 
  glRotatef(35.0,1.0,1.0,1.0); 
 
//将原来网格的绘制部分注释掉,代替以填充曲面的绘制方法 
  glEvalMesh2(GL_FILL,0,20,0,20); 
  int i,j; 
/*  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(); 
 } 
*/ 
 
  glPointSize(4.0); 
  glBegin(GL_POINTS); 
  for(i=0;i<4;i++) 
  for(j=0;j<4;j++) 
  { 
      glColor3fv(color[i]); 
          glVertex3fv(&points[i][j][0]); 
  } 
  glEnd(); 
  glPopMatrix(); 
  glFlush(); 
 
 

void main(void) 

        myinit(); 
     
    auxReshapeFunc(reshape); 
    auxMainLoop(display); 

//end of sample 
//////////////////////////////////////////////////////////////// 
一个真正具有实体的曲面就展现出来乐。控制点的不同,可以控制曲面的形状 
可以看出OPENGL的强大功能,只用很少的原代码就产生真实的3D效果。 
在以此篇结束复杂建模前,给出一个绘制NURBS曲面(非均匀B样条曲面)的例子, 
这里用到乐一些OPENGL实用库提供的专门函数。所有的新东东都在程序中做乐注 
释,注释给出过程的含义,具体函数的操作可以详细查阅联机手册。 
/////////////////////////////////////////////////////////////// 
//sample.cpp 
#include "glos.h" 
#include <GL/gl.h> 
#include <GL/glaux.h> 
#include "windows.h" 
 
void myinit(void); 
void CALLBACK  display(void); 
void CALLBACK  reshape(GLsizei w,GLsizei h); 
 
//定义一组控制点的存储空间 
GLfloat points[4][4][3]; 
//定义一个指向NURBS曲面对象的指针 
GLUnurbsObj *theNurb; 
 
//用来生成控制点的过程,取代被注释掉的原来直接赋值方式生成控制点 
void init_surface(void) 

        int u,v; 
        for(u=0;u<4;u++) 
        { 
                for(v=0;v<4;v++) 
                { 
                        points[u][v][0]=2.0*((GLfloat)u-1.5); 
                        points[u][v][1]=2.0*((GLfloat)v-1.5); 
                        if((u==1||u==2)&&(v==1||v==2)) 
                                points[u][v][2]=3.0; 
                else 
                        points[u][v][2]=-3.0; 
                } 
        } 

/*                        
GLfloat points[4][4][3]={ 
        {{-1.5,-1.5,2.0},{-0.5,-1.5,4.0}, 
        {0.5,-1.5,3.0},{1.5,-1.5,2.0}}, 
        {{-1.5,-0.5,3.0},{-0.5,1.5,4.0}, 
        {0.5,0.5,2.0},{1.5,-0.5,-1.0}}, 
        {{-1.5,0.5,2.0},{-0.5,0.5,4.0}, 
        {0.5,0.5,5.0},{1.5,-1.5,1.5}}, 
        {{-1.5,1.5,-2.0},{-0.5,1.5,3.0}, 
        {0.5,0.5,1.0},{1.5,1.5,-1.0}}}; 
*/ 
GLfloat color[4][3]={ 
        {1.0,0.0,0.0},{0.0,1.0,0.0},{0.0,0.0,1.0},{1.0,1.0,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); 
//首先初始化控制点 
        init_surface(); 
//创建一个NURBS曲面的对象 
        theNurb=gluNewNurbsRenderer(); 
//修改此曲面对象的属性 
        gluNurbsProperty(theNurb,GLU_SAMPLING_TOLERANCE,25.0); 
        gluNurbsProperty(theNurb,GLU_DISPLAY_MODE,GLU_FILL); 

 
void myinit(void) 

 
        auxInitDisplayMode(AUX_SINGLE|AUX_RGBA); 
        auxInitPosition(0,0,500,500); 
        auxInitWindow("sample1"); 
        glClearColor(0.0,0.0,0.0,0.0); 
        glClear(GL_COLOR_BUFFER_BIT); 
 
        glMap2f(GL_MAP2_VERTEX_3,0,1,3,4,0,1,12,4,&points[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); 
 
        glEnable(GL_DEPTH_TEST); 
        initlights(); 
//      glShadeModel(GL_FLAT); 

 
void CALLBACK reshape(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)h/(GLfloat)w, 
         5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0,-5.0,5.0); 
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity(); 

 
 
void CALLBACK display(void) 

//B样条曲面(NURBS)的控制向量,可以参阅图形学的相关书籍 
  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); 
  glColor3f(0.0,0.0,1.0); 
  glPushMatrix(); 
  glRotatef(35.0,1.0,1.0,1.0); 
  glRotatef(-60.0,1.0,0.0,0.0); 
  glScalef(0.5,0.5,0.5); 
 
//注释掉原来的曲面绘制函数,代之以新的NURBS曲面绘制函数 
  //  glEvalMesh2(GL_FILL,0,20,0,20); 
//定义曲面的数学模型,确定其形状 
  gluNurbsSurface(theNurb, 
          8,knots, 
          8,knots, 
          4*3, 
          3, 
          &points[0][0][0], 
          4,4, 
          GL_MAP2_VERTEX_3); 
//结束曲面的绘制,此结构很类似于标准的glBegin()...glEnd() 
  gluEndSurface(theNurb); 
 
  int i,j; 
  glPointSize(4.0); 
  glBegin(GL_POINTS); 
  for(i=0;i<4;i++) 
  for(j=0;j<4;j++) 
  { 
      glColor3fv(color[i]); 
          glVertex3fv(&points[i][j][0]); 
  } 
  glEnd(); 
  glPopMatrix(); 
  glFlush(); 
 
 

void main(void) 

        myinit(); 
     
    auxReshapeFunc(reshape); 
    auxMainLoop(display); 

//end of sample 
////////////////////////////////////////////////////////////////// 
至此,复杂建模告于段落。下次介绍特殊光照 
 
-- 
※ 来源:·BBS 水木清华站 bbs.net.tsinghua.edu.cn·[FROM: 166.111.74.90]