荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Peter (小飞侠), 信区: Program
标  题: OPENGL(14)
发信站: BBS 荔园晨风站 (Fri Jan 22 08:21:27 1999), 转信


曲面的构造可以是网格线和填充曲面形式,其实与曲线很类似只是变为
二维而已。
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.szu.edu.cn.[FROM: 192.168.1.3]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店