OpenGL系统设计-扩展建模(5)

 

1.1        NURBS

非均匀有理样条NURBS(Non-Uniform Rational B-Splines)是近年来发展迅速,应用广泛的一种表示曲线曲面造型技术。它能够精确地表示二次规则曲线曲面,从而能用统一的数学形式表示规则曲面与自由曲面,具有可影响曲线曲面形状的权因子,使形状更宜于控制和实现。1991年国际标准化组织颁布了关于工业产品数据交换的STEP国际标准,将NURBS方法作为定义工业产品几何形状的唯一数学描述方法,从而使NURBS方法成为曲面造型技术发展趋势中最重要的基础。 

OpenGLNURBS的支持是通过实用库实现的,相应的函数有

gluNewNurbsRenderer

gluNurbsProperty

gluNurbsSurface

gluBeginSurface

gluEndSurface

gluDeleteNurbsRenderer

 

创建NURBS曲面时,首先使用gluNewNurbsRenderer创建一个NURBS对象,然后使用gluNurbsProperty设置NURBS对象的属性。gluBeginSurface~gluEndSurface的作用类似glBegin~glEnd,在两个函数间使用gluNurbsSurface来定义NURBS曲面的具体形状。gluEndSurface完成了NURBS曲面的定义后就可以显示了。需要注意的是,不再使用NURBS对象时,要记得使用gluDeleteNurbsRenderer释放掉其对象所占用的内存。

gluNewNurbsRenderer函数不带任何参数,调用成功后返回一个GLUnurbsObj类型的指针,指向创建成功的NURBS对象。其原型如下

 
GLUnurbsObj* gluNewNurbsRenderer( void );
 

创建NURBS对象的代码类似如下

 

GLUnurbsObj *theNurb;
theNurb = gluNewNurbsRenderer();
 

接下来,要使用gluNurbsProperty来设置theNurb的属性。gluNurbsProperty的原型如下

 
void gluNurbsProperty(
  GLUnurbsObj *nobj,
  GLenum property,
  GLfloat value
);

nobj 参数就是使用gluNewNurbsRenderer创建的NURBS对象。property 是需要设置的属性,可以取的值如下表10-2所示。

 

10-2   gluNurbsProperty参数含义

Property取值

含义

GLU_SAMPLING_TOLERANCE

当抽样方法设置为GLU_PATH_LENGTH时指定抽样误差,单位是像素。缺省值为50.0

GLU_DISPLAY_MODE

使用value参数来定义NURBS曲面的渲染方式,此时value可以取值GLU_FILLGLU_OUTLINE_POLYGONGLU_OUTLINE_PATCH

GLU_FILL表示曲面填充多边形方式渲染,曲面是一个整体的平滑曲面,这也是缺省的方式。

GLU_OUTLINE_POLYGON表示曲面仅仅画出由小方格组成的外轮廓,表现出来的就是网格曲面。

GLU_OUTLINE_PATCH则纯粹是一个外轮廓边沿。

GLU_CULLING

value 参数是一个BOOL型的数值,确定NURBS曲线是否丢弃视点范围之外的控制点,缺省为GL_FALSE

GLU_AUTO_LOAD_MATRIX

value 参数是一个BOOL型的数值。当为GL_TRUE时,表示NURBS要从OpenGL服务器下载投影矩阵,模型观察矩阵和视点来计算对每一个NURBS曲线计算抽样和消隐矩阵。当valueGL_FALSE时,表示必须由本地应用提供投影矩阵,模型观察矩阵和视点。对于非网络应用来说,该项可以忽略。

GLU_PARAMETRIC_TOLERANCE

当抽样方法为GLU_PARAMETRIC_ERROR时指定最大距离,单位是像素,缺省值为0.5

GLU_SAMPLING_METHOD

指定怎样利用方格拼成NURBS曲面,即拟合NURBS的方法。对应的value可以取GLU_PATH_LENGTHGLU_PARAMETRIC_ERRORGLU_DOMAIN_DISTANCE

value取值为GLU_PATH_LENGTH(缺省值)时,用于组成曲面的小方格的边长最大不超过以GLU_SAMPLING_TOLERANCE设置的值。

value取值为GLU_PARAMETRIC_ERROR时,以 GLU_PARAMETRIC_TOLERANCE指定的最大距离值在小方格和整个表面之间。

value取值为GLU_DOMAIN_DISTANCE时,指明在uv方向上每单位长度有多少个抽样点。

GLU_U_STEP

指定沿u方向每单位长度的采样点数,当LU_SAMPLING_METHOD设置成GLU_DOMAIN_DISTANCE GLU_U_STEP有效。缺省为100

GLU_V_STEP

指定沿v方向每单位长度的采样点数,当LU_SAMPLING_METHOD设置成GLU_DOMAIN_DISTANCE GLU_U_STEP有效。缺省为100

 

value 表示property的值,它可以是一个数字,也可以是GLU_PATH_LENGTH GLU_PARAMETRIC_ERRORGLU_DOMAIN_DISTANCE三者之一。

 

下面是一个NURBS曲面的生成代码。

 

//NURBS对象

GLUnurbsObj *theNurb;

 

//三种显示模式

GLfloat DisplayMode[3] = {GLU_FILL, GLU_OUTLINE_POLYGON, GLU_OUTLINE_PATCH};

int Mode = 0;                   //缺省的显示模式为GLU_FILL

BOOL bModePressed = FALSE;  //改变显示模式选择按键

 

//改变显示模式的按键处理在WndProc

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

    switch (message)

    {

    case WM_ACTIVATE:

    ……   

    case WM_SIZE:

        ……

    case WM_KEYDOWN:

        switch(wParam)

        {

        case VK_ESCAPE:

            PostQuitMessage(0);

            return 0;

        case VK_SPACE:              //空格键进行显示模式切换

            bModePressed = TRUE;

            Mode ++;

            if(Mode >2)

                Mode = 0;

            break;

        }

        break;

        case WM_DESTROY:

            PostQuitMessage(0);

            break;

        default:

            return DefWindowProc(hWnd, message, wParam, lParam);

    }

    return 0;

}

 

glInit()中,我们来建立一个光源,并且创建一种材质,将其应用到NURBS曲面上。

 

int glInit()

{

   

    //启用阴影平滑(Smooth Shading)

    glShadeModel(GL_SMOOTH);

 

    //设置深度缓冲

    glClearDepth(1.0f);

 

    //启动深度测试

    glEnable(GL_DEPTH_TEST);

 

    //深度测试的类型

    glDepthFunc(GL_LEQUAL);

 

    //进行透视修正

    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

   

    //翡翠、祖母绿

    GLfloat mat_ambient[] = { 0.021500, 0.174500, 0.021500, 0.550000 };

    GLfloat mat_diffuse[] = { 0.075680, 0.614240, 0.075680, 0.550000 };

    GLfloat mat_specular[] = {0.633000, 0.727811, 0.633000, 0.550000};

    GLfloat mat_shininess[] = {76.800003 };

    glColor3f(1.0f, 1.0f, 1.0f);

   

    //材质属性 

    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);

    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);

    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);

    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);

 

    //启动光照,使用缺省的光照参数 

    glEnable(GL_LIGHTING);

    glEnable(GL_LIGHT0);

 

    //自动计算法向量

    glEnable(GL_AUTO_NORMAL);

 

    //创建一个新的NURBS对象

    theNurb = gluNewNurbsRenderer();

 

    //设置NURBS对象的参数

    gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0);

    gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL);

 

    return TRUE;

}

 

glShutdown中必须添加将NURBS对象释放的代码,否则,即便应用程序关闭,对象占用的内存也可能会一直无法释放。

 

void glShutdown()

{

    ……

    if(theNurb)

        gluDeleteNurbsRenderer(theNurb);

}

 

//定义NURBS的控制点,共25

GLfloat CtlPoints[5][5][3]=

{

    {{-3.0, -3.0, -3.0}, {-3.0, -1.0, -3.0}, {-3.0, 0.0, -3.0},

{-3.0, 1.0, -3.0}, {-3.0, 3.0, -3.0}},

 

    {{-1.0, -3.0, -3.0}, {-1.0, -1.0, -9.0}, {-1.0 ,0.0, 9.0},

{-1.0, 1.0, -9.0}, {-1.0, 3.0, -3.0}},

 

    {{1.0, -3.0, -3.0}, {1.0, -1.0, 3.0}, {1.0, 0.0, 3.0,},

{1.0, 1.0, 3.0}, {1.0, 3.0, -3.0}},

 

    {{3.0, -3.0, -3.0}, {3.0, -1.0, -3.0},{3.0, 0.0, -3.0},

 {3.0, 1.0, -3.0},{3.0, 3.0, -3.0}},

 

    {{5.0, -3.0, -3.0}, {5.0, -1.0, -9.0},{5.0, 0.0, 9.0},

{5.0, 1.0, -9.0},{5.0, 3.0, -3.0}}

};

 

 

GLfloat knots[10] = {0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0};

 

void glMain()

{

   

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();   //加载单位矩阵

    glTranslatef(0.0f, -1.0f, -10.0f);

    glRotatef(90, 0.0f, 0.0f, 1.0f);

 

    //根据按键确定切换显示模式     

    if(bModePressed)

    {

        bModePressed = FALSE;

        gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, DisplayMode[Mode]);

    }

   

    //开始定义NURBS曲面   

    gluBeginSurface(theNurb);

    gluNurbsSurface(theNurb,

        10,

        knots,

        10,

        knots,

        15,

        3,

        &CtlPoints[0][0][0],

        5, 5,

        GL_MAP2_VERTEX_3);

    gluEndSurface(theNurb);     //结束曲面定义并显示

   

    SwapBuffers(g_hDC);//交换前后缓冲区

} 

 

程序运行后,可以看到一个脸部模型的大概轮廓已经显示出来。当然,真正的实现一个完整的面具模型还需要更多的控制点。按空格键后还可以看到网格状的曲面和仅有外边沿轮廓的曲面,仅有外边沿轮廓的曲面基本上已经看不出是一个曲面了,更象一个平面多边形。效果如图10-11所示。

OpenGL系统设计-扩展建模(5)_第1张图片

你可能感兴趣的:(domain,buffer,扩展,Path,patch,distance)