zoukankan      html  css  js  c++  java
  • OpenGl中的Nurbs B样条曲面绘制

    NURBS

    贝塞尔曲线的缺点是当我们增加很多控制点的时候,曲线变得不可控,其连续性会变差差。如果控制点很多(高阶曲线),当我们调整一个控制点的位置,对 整个曲线的影响是很大的。要获得更高级的控制,可以使用GLU库提供的NURBS(非均匀有理B样条)。通过这些函数我们可以在求值器中调整控制点的影响 力,在有大量控制点的情况下,依然可以产生平滑的曲线。

    从贝塞尔到B样条

    贝塞尔曲线由起点、终点和其他控制点来影响曲线的形状。在二次贝塞尔曲线和三次贝塞尔曲线中,可以通过调整控制点的位置而得到很好的平滑性(C2级 连续性 曲率级)的曲线。当增加更多的控制点的时候,这种平滑性就被破坏了。如下图所示,前两个曲线很平滑(曲率级的连续性),第三个曲线在增加了一个控制点之 后,曲线被拉伸了,其平滑性遭到了破坏。

      image

    B样条的工作方式类似于贝塞尔曲线,但不同的是曲线被分成很多段。每段曲线的形状只受到最近的四个控制点的影响,这样曲线就像是4阶的贝塞尔曲线拼接起来的。这样很长的有很多控制点的曲线就会有固定的连续性,平滑性(每一段都是c2级的连续性)。

    结点

    NURBS(非均匀有理B样条)的真正威力在于,可以调整任意一段曲线中的四个控制点的影响力,来产生较好的平滑性。这是通过一系列结点来控制的。每个控制点都定义了两个结点的值。结点的取值范围是u或v的定义域,而且必须是非递减的。

    结点的值决定了落在u、v参数定义域内的控制点的影响力。下图的曲线表示控制点对一条在u参数定义域内的具有四个单位的曲线的影响。下图表示中间点对曲线的影响更大,而且只有在[0,3]范围内的控制点才会对曲线产生影响。

    image

    在u、v参数定义域内的控制点对曲线的形状会有有影响,而且我们可以通过结点来控制控制点的影响力。非均匀性就是指一个控制点的影响力的范围是可以改变的。

    以下内容及节选自 http://www.rhino3d.com/cn/nurbs

    节点 ( Knot ) 是一个 ( 阶数 + N - 1 ) 的数字列表,N 代表控制点数目。有时候这个列表上的数字也称为节点矢量 ( Knot Vector ),这里的矢量并不是指 3D 方向。

    节点列表上的数字必须符合几个条件,确定条件是否符合的标准方式是在列表上往下时,数字必需维持不变或变大,而且数字重复的次数不可以比阶数大。例 如,阶数 3 有 15 个控制点的 NURBS 曲线,列表数字为 0,0,0,1,2,2,2,3,7,7,9,9,9 是一个符合条件的节点列表。列表数字为 0,0,0,1,2,2,2,2,7,7,9,9,9 则不符合,因为此列表中有四个 2,而四比阶数大 ( 阶数为 3 )。

    节点值重复的次数称为节点的重数 ( Multiplicity ),在上面例子中符合条件的节点列表中,节点值 0 的重数值为三;节点值 1 的重数值为一;节点值 2 的重数为三;节点值 7 的重数值为二;节点值 9 的重数值为三。如果节点值重复的次数和阶数一样,该节点值称为全复节点 ( Full-Multiplicity Knot )。在上面的例子中,节点值 0、2、9 有完整的重数,只出现一次的节点值称为单纯节点 ( Simple Knot ),节点值 1 和 3 为单纯节点。

    如果在节点列表中是以全复节点开始,接下来是单纯节点,再以全复节点结束,而且节点值为等差,称为均匀 ( Uniform )。例如,如果阶数为 3 有 7 个控制点的 NURBS 曲线,其节点值为 0,0,0,1,2,3,4,4,4,那么该曲线有均匀的节点。如果节点值是 0,0,0,1,2,5,6,6,6 不是均匀的,称为非均匀 ( Non-Uniform )。在 NURBS 的 NU 代表“非均匀”,意味着在一条 NURBS 曲线中节点可以是非均匀的。

    在节点值列表中段有重复节点值的 NURBS 曲线比较不平滑,最不平滑的情形是节点列表中段出现全复节点,代表曲线有锐角。因此,有些设计师喜欢在曲线插入或移除节点,然后调整控制点,使曲线的造型 变得平滑或尖锐。因为节点数等于 ( N + 阶数 - 1 ),N 代表控制点的数量,所以插入一个节点会增加一个控制点,移除一个节点也会减少一个控制点。插入节点时可以不改变 NURBS 曲线的形状,但通常移除节点必定会改变 NURBS 曲线的形状。

    节点(Knot)与控制点

    控制点和节点是一对一成对的是常见的错误概念,这种情形只发生在 1 阶的 NURBS ( 多重直线 )。较高阶数的 NURBS 的每 ( 2 x 阶数 ) 个节点是一个群组,每 ( 阶数 + 1 ) 个控制点是一个群组。例如,一条 3 阶 7 个控制点的 NURBS 曲线,节点是 0,0,0,1,2,5,8,8,8,前四个控制点是对应至前六个节点;第二至第五个控制点是对应至第二至第七个节点 0,0,1,2,5,8;第三至第六个控制点是对应至第三至第八个节点 0,1,2,5,8,8;最后四个控制点是对应至最后六个节点

    创建NURBS表面

    GLU库中提供了易用高级的绘制NURBS表面的函数。我们不需要显示地调用求值函数或建立网格。渲染一个NURBS表面的步骤如下:

    1. 创建一个NURBS渲染对象 gluNewNurbsRenderer()
    2. 调用相关的NURBS函数来修改曲线或曲面的外观 gluNurbsProperty
    3. 定义表面,渲染NURBS gluBeginSurface gluNurbsSurface gluEndSurface
    4. 销毁NURBS渲染对象 gluDeleteNurbsRenderer();

    我们通过gluNewNurbsRenderer函数来为NURBS创建一个渲染器对象,在最后使用gluDeleteNurbsRenderer销毁它。代码如下:

    // NURBS 对象指针 GLUnurbsObj * pNurb = NULL; ... ... // 创建NURBS对象 pNurb = gluNewNurbsRenderer(); ... if (pNurb) gluDeleteNurbsRenderer(pNurb);

    NURBS属性

    在创建了NURBS渲染器之后,我们需要设置NURBS的属性。

    //设置采样容差

    gluNurbsProperty(pNurb, GLU_SAMPLING_TOLERANCE, 25.0f);

    //填充一个实体的表面

    gluNurbsProperty(pNurb, GLU_DISPLAY_MODE, (GLfloat)GLU_FILL);

    GLU_SAMPLING_TOLERANCE决定了网格的精细程度。GLU_FILL表示使用填充模式,相应的GLU_OUTLINE_POLYGON是线框模式。

    定义表面

    表面通过一组控制点和一个结点序列来定义。使用gluNurbsSurface函数来定义表面,这个函数要在gluBeginSurface和gluEndSurface中间:

    // 渲染NURB // 开始NURB表面的定义 gluBeginSurface(pNurb); gluNurbsSurface(pNurb, // 指针指向NURBS渲染器 8 , Knots, // u定义域内的结点个数,以及结点序列 8 , Knots, // v定义域内的结点个数,以及结点序列 4 * 3 , // u方向上控制点的间隔 3 , // v方向上控制点的间隔 & ctrlPoints[ 0 ][ 0 ][ 0 ], // 控制点数组 4 , 4 , // u,v 的次数 GL_MAP2_VERTEX_3); // 表面的类型 // 完成定义 gluEndSurface(pNurb);
     
    程序如下:
     1     float ctrlpoints[4][4][3]={   
     2         {{100.0,270.0,0.0},//p00   
     3         {105.0,180.0,0.0},//p01   
     4         {110.0,160.0,0.0},//p02   
     5         {155.0,100.0,0.0}},//p03   
     6         {{180.0,200.0,0.0},//p10   
     7         {190.0,130.0,0.0},//p11   
     8         {200.0,110.0,0.0},//p12   
     9         {240.0,70.0,0.0}},//p13   
    10         {{310.0,200.0,0.0},//p20   
    11         {320.0,130.0,0.0},//p21   
    12         {330.0,110.0,0.0},//p22   
    13         {370.0,70.0,0.0}},//p23   
    14         {{420.0,270.0,0.0},//p30   
    15         {430.0,180.0,0.0},//p31   
    16         {440.0,160.0,0.0},//p32   
    17         {490.0,120.0,1.0}}//p33   
    18     };  
    19 
    20     glPushMatrix();
    21     //绘制控制点与控制线
    22     glScaled(0.2, 0.2, 0.2);
    23 
    24     glPointSize(4.0f); 
    25     glColor3f(0.0, 0.0, 1.0);
    26     glColor3f(0, 0, 1);
    27     glBegin(GL_POINTS);
    28     for (int i = 0; i < 4; i++)
    29     {
    30         for (int j = 0; j < 4; j++)
    31             glVertex3fv(ctrlpoints[i][j]);
    32 
    33     }
    34     glEnd();
    35     //绘制控制线
    36     glLineWidth(1.5f);
    37     glColor3f(0.0,1.0,1.0); 
    38     for (int i = 0; i < 4; i++)
    39     {
    40         glBegin(GL_LINE_STRIP);
    41         for (int j = 0; j < 4; j++)
    42             glVertex3fv(ctrlpoints[i][j]);
    43         glEnd();
    44 
    45         glBegin(GL_LINE_STRIP);
    46         for (int j = 0; j < 4; j++)
    47             glVertex3fv(ctrlpoints[j][i]);
    48         glEnd();
    49     }
    50     //绘制B样条控制曲面
    51      GLfloat knots[8]={0.0,0.0,0.0,0.0,1.0,1.0,1.0,1.0}; //B样条控制向量
    52     glLineWidth(1.0f);
    53     glColor3f(0.0, 0.0, 0.0);
    54     
    55     gluNurbsProperty(pNurb,GLU_SAMPLING_TOLERANCE,25.0); //设置属性
    56     gluNurbsProperty(pNurb,GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON); 
    57     gluBeginSurface(pNurb);//开始绘制
    58     gluNurbsSurface(pNurb, 
    59         8,knots, 
    60         8,knots, 
    61         4*3, 
    62         3, 
    63         &ctrlpoints[0][0][0], 
    64         4, 4, 
    65         GL_MAP2_VERTEX_3);
    66 
    67     gluEndSurface(pNurb); //结束绘制
    68 
    69 for (int j = 0; j <= 8; j++) 70 { 71 glBegin(GL_LINE_STRIP); 72 for (int i = 0; i <= 30; i++) 73 glEvalCoord2f((GLfloat)i/30.0, (GLfloat)j/8.0); 74 glEnd(); 75 glBegin(GL_LINE_STRIP); 76 for (int i = 0; i <= 30; i++) 77 glEvalCoord2f((GLfloat)j/8.0, (GLfloat)i/30.0); 78 glEnd(); 79 } 80 glPopMatrix();

      程序运行效果如下:

      

  • 相关阅读:
    (Good Bye 2019) Codeforces 1270B Interesting Subarray
    (Good Bye 2019) Codeforces 1270A Card Game
    Codeforces 1283D Christmas Trees(BFS)
    Codeforces 1283C Friends and Gifts
    Codeforces 1283B Candies Division
    1095 Cars on Campus (30)
    1080 Graduate Admission (30)
    1099 Build A Binary Search Tree (30)
    1018 Public Bike Management (30)
    1087 All Roads Lead to Rome (30)
  • 原文地址:https://www.cnblogs.com/icmzn/p/5089185.html
Copyright © 2011-2022 走看看