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所示。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NURBS是一种非常优秀的建模方式,在高级三维软件当中都支持这种建模方式。NURBS能够比传统的网格建模方式更好地控制物体表面的曲线度,从而能够创建出更逼真、生动的造型。NURBS曲线和NURBS曲面在传统的制图领域是不存在的,是为使用计算机进行3D建模而专门建立的。在3D建模的内部空间用曲线和曲面来表现轮廓和外形。它们是用数学表达式构建的,NURBS数学表达式是一种复合体。在这一章里,只是简要地介绍一下NURBS的概念,来帮助了解怎样建立NURBSNURBS物体为什么会有这样的表现。 1.1 NURBS的定义 NURBS是Non-Uniform Rational B-Splines的缩写,是非统一有理B样条的意思。具体解释是: 。Non-Uniform(非统一):是指一个控制顶点的影响力的范围能够改变。当创建一个不规则曲面的时候这一点非常有用。同样,统一的曲线和曲面在透视投影下也不是无变化的,对于交互的3D建模来说这是一个严重的缺陷。 。Rational(有理):是指每个NURBS物体都可以用数学表达式来定义。 。B-Spline(B样条):是指用路线来构建一条曲线,在一个或更多的点之间以内插值替换的。 简单地说,NURBS就是专门做曲面物体的一种造型方法。NURBS造型总是由曲线和曲面来定义的,所以要在NURBS表面里生成一条有棱角的边是很困难的。就是因为这一特点,我们可以用它做出各种复杂的曲面造型和表现特殊的效果,如人的皮肤,面貌或流线型的跑车等。 1.2 度数和连续性 所有的曲线都有Degree(度数)。一条曲线的度数在表现所使用的等式里面是最主要的指数。一个直线的等式度数是1,一个二次的等式度数是2.NURBS曲线表现是立方等式,度数是3.可以把度数设得很高,但通常不必要这样做。虽然度数越高曲线越圆滑,但计算时间也越长。一般只要记住Degree(度数)值越高曲线越圆滑就可以了。 曲线也都有Continuity(连续性)。一条连续的曲线是不间断的。连续性有不同的级别,一条曲线有一个角度或尖端,它的连续是是C0.一条曲线如果没有尖端但曲率有改变,连续性是C1.如果一条曲线是连续的,曲率不改变,连续性是C2,如图所示。 一条曲线可以有较高的连续性,但对于计算机建模来说这三个级别已经够了。通常眼睛不能区别C2连续性和更高的连续性之间的差别。 连续性和度数是有关系的。一个度数为3的等式能产生C2连续性曲线。NURBS造型通常不需要这么高度数的曲线。 一条不同片断的NURBS曲线可以用不同级别的连续性。具体来说,在同样的位置或非常靠近的地方放置一些可控点,会降低连续性的级别。两个重叠的可控点会使曲率变尖锐。三个重叠的可控点会在曲线里建立一个有角度的尖角。附加一个或两个可控点会在曲线的附近联合它们的影响力。 从可控点中删除一个离开它们,就增加了曲线的连续性的级别。在3DMAX里,Fuse(熔化)可控点会在曲线里建立一个假象的曲率或尖角。如果要恢复原状,Unfuse(反熔化)那个点就可以了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值