OpenGL学习笔记(四):曲线曲面

作者:yurunsun@gmail.com 新浪微博@孙雨润 新浪博客 CSDN博客

日期: 2013-6-13

本章内容:

  1. 凹多边形分格化
  2. 二次方程表面
  3. 求值器
  4. NURBS

1. 凹多边形分格化

OpenGL显示凹多边形时必须先分解为简单凸多边形,这种划分方法称为多边形分格化(tesselation),glu提供一组函数接受复杂多边形轮廓线,返回一些三角形、三角形网、三角形扇以及直线的组合。

  1. 创建一个新的分格化对象

    GLUtesselator* gluNewTess(void);
    
  2. 注册回调函数

    void gluTessCallback(GLUtesselator *tessobj, GLenum type, void (*fn)());
    
  3. 指定分格化属性,例如环绕规则来确定哪些区域填充、哪些不该着色

    void gluTessProperty(GLUtesselator *tessobj, GLenum property, GLdouble value);
    void gluTessNormal(GLUtesselator *tessobj, GLdouble x, GLdouble y, GLdouble z);
    
  4. 指定一个或多个闭合多边形的轮廓线来渲染经过分格化的多边形,最好将分格化后的多边形放入显示列表中

    void gluTessBeginPolygon(GLUtesselator *tessobj, void *user_data);
    void gluNextContour(GLUtriangulatorObj *tessobj, GLenum type);
    void gluTessEndPolygon(GLUtesselator *tessobj);
    
    void gluTessBeginContour(GLUtesselator *tessobj);
    void gluNextContour(GLUtriangulatorObj *tessobj, GLenum type);
    void gluTessEndContour(GLUtesselator *tessobj);
    void gluTessVertex(GLUtesselator *tessobj, GLdouble coords[3], void *vertex_data);
    
  5. 继续使用此分格化对象,或者删除

    void gluDeleteTess(GLUtesselator *tessobj);
    

2. 二次方程表面

使用glu创建和渲染二次方程表面步骤如下:

  1. gluNewQuadric()函数创建一个二次方程对象
  2. 指定这个二次方程对象的属性
    • gluQuadricOrientation()函数控制环绕方向,区分内部外部区域
    • gluQuadricDrawStyle()函数选择把物体渲染成点、直线、填充多边形
    • gluQuadricNormal()函数为每个顶点或每个面指定一条法线
    • gluQuadricTexture()函数生成纹理坐标
  3. gluQuadricCallback()函数注册一个错误处理函数
  4. 根据需要调用相应二次方程表面渲染函数:

    gluSphere();
    gluCylinder();
    gluDisk();
    gluPartialDisk();
    
  5. gluDeleteQuadric()销毁二次方程对象

3. 求值器

3.1 一维求值器

GLfloat ctrlpoints[4][3] = {{ -4.0, -4.0, 0.0}, { -2.0, 4.0, 0.0}, 
                            {2.0, -4.0, 0.0}, {4.0, 4.0, 0.0}};
void init(void) {
    glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]);
    glEnable(GL_MAP1_VERTEX_3);
}
void display(void) {
    glBegin(GL_LINE_STRIP);
        for (int i = 0; i <= 30; i++) 
            glEvalCoord1f((GLfloat) i/30.0);
    glEnd();
}

使用下面函数定义一维求值器:

void glMap1f(GLenum target, float u1, float u2, GLint stride, GLint order, const float *points);

GL_MAP1_VERTEX_3            //x, y, zvertex coordinates
GL_MAP1_VERTEX_4            //x, y, z, wvertex coordinates
GL_MAP1_INDEX               //color index
GL_MAP1_COLOR_4             //R, G, B, A
GL_MAP1_NORMAL              //normal coordinates
GL_MAP1_TEXTURE_COORD_1     //stexture coordinates
GL_MAP1_TEXTURE_COORD_2     //s, ttexture coordinates
GL_MAP1_TEXTURE_COORD_3     //s, t, rtexture coordinates
GL_MAP1_TEXTURE_COORD_4     //s, t, r, qtexture coordinates
  • target: GLMAP1VERTEX_3表示指定了应用程序提供的三维控制点以及应该产生的三维顶点
  • u1: 0.0表示参数u的低值
  • u2: 1.0表示参数u的高值
  • stride: 3表示从一个控制点跳到下一个控制点时应该推进多少浮点值
  • order: 4表示样条的阶数
  • points: &ctrlpoints[0][0]表示指向第一个控制点的数据的指针

下面函数对已启用的求值器执行计算:

void glEvalCoord1{fd}(TYPE u);
void glEvalCoord1{fd}v(const TYPE *u);

可以一次使用多个求值器进行计算,即如果定义并启用了GL_MAP1_VERTEX_3和一个GL_MAP1_COLOR_4,就可以调用`glEvalCoord1()函数同时生成一个位置和一种颜色。

3.2 一维均匀求值器

在上例中课件使用了i/30,即使u值均匀分布。更方便的方法是调用glMapGrid1f()函数定义一个一维网格,然后使用glEvalMesh1()函数应用这个网格。

void glMapGrid1{fd}(GLint n, TYPE u1, TYPE u2);
void glEvalMesh1(GLenum mode, GLint p1, GLint p2);

第二个函数相当于

glBegin(GL_POINTS);
    for (i = p1; i <= p2; i++) 
        glEvalCoord1(u1 + i*(u2-u1)/n);
glEnd();

3.3 二维求值器

与一维求值器的区别就是需要考虑两个参数u和v.

void glMap2{fd}(GLenum target, TYPE u1, TYPE u2, GLint ustride,
                GLint uorder,TYPE v1, TYPE v2, GLint vstride,
                GLint vorder, TYPE points);
void glEvalCoord2{fd}(TYPE u, TYPE v);
void glEvalCoord2{fd}v(const TYPE *values);

同样有二维均匀求值器:

void glMapGrid2{fd}(GLint nu,TYPE u1, TYPE u2, GLint nv,TYPE v1, TYPE v2);
void glEvalMesh2(GLenummode, GLint i1, GLint i2, GLint j1, GLint j2);

4. NURBS接口

GLU建立在OpenGL求值器函数的基础上提供了NURBS接口。使用步骤如下:

  1. glEnable(GL_AUTO_NORMAL)自动生成法线(也可以自己计算)
  2. gluNewNurbsRENDERER()创建指向NURBS对象的指针
  3. gluNurbsProperty()选择渲染属性
  4. gluNurbsCallback()注册错误回调函数
  5. gluBeginCurve()/gluBeginSurface()声明开始绘制曲线曲面
  6. gluNurbsCurve()/gluNurbsSurface()生成和渲染曲线曲面
  7. gluEndCurve()/gluEndSurface()声明结束绘制曲线曲面

下面重点解释其中几个步骤:

4.1 选择渲染属性

voidgluNurbsProperty(GLUnurbsObj *nobj, GLenum property, GLfloat value);

GLU_DISPLAY_MODE,               // GLU_FILL, GLU_OUTLINE_POLYGON, GLU_OUTLINE_PATCH
GLU_NURBS_MODE,                 // GLU_NURBS_RENDERER, GL_NURBS_TESSELLATOR
GLU_CULLING,                    //
GLU_SAMPLING_METHOD,            // GLU_PATH_LENTH, GLU_PARAMETRIC_ERROR, GLU_DOMAIN_DISTANCE
GLU_SAMPLING_TOLERANCE,         
GLU_PARAMETRIC_TOLERANCE, 
GLU_U_STEP, GLU_V_STEP, 
GLU_AUTO_LOAD_MATRIX            // 是否需要从openGL服务器下载投影矩阵、模视矩阵和视口 否则使用:

void gluLoadSamplingMatrices(GLUnurbsObj *nobj,
        const GLfloat modelMatrix[16], 
        const GLfloat projMatrix[16], 
        const GLint viewport[4]);

4.2 创建并绘制曲线曲面

void gluNurbsSurface(GLUnurbsObj *nobj, GLint uknot_count,
        GLfloat *uknot, GLint vknot_count, GLfloat *vknot,
        GLint u_stride, GLint v_stride, GLfloat *ctlarray,
        GLint uorder, GLint vorder, GLenum type);

gluBeginSurface(nobj);
    gluNurbsSurface(nobj, ..., GL_MAP2_TEXTURE_COORD_2);
    gluNurbsSurface(nobj, ..., GL_MAP2_NORMAL);
    gluNurbsSurface(nobj, ..., GL_MAP2_VERTEX_3);
gluEndSurface(nobj);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值