在3D空间中绘制三角形

来源:互联网 发布:淘宝网闲鱼在哪里 编辑:程序博客网 时间:2024/05/04 08:32

在3D空间中绘制三角形


        在OpenGL中,要绘制一个实心的表面,仅仅靠点和线是不够的,还需要使用多边形。多边形是一种闭合的形状,可以用当前选择的颜色进行填充(也可以选择不填充),它是OpenGL中所有实心物体的组成基础。

        最简单的多边形是三角形,它只有三条边。图元GL_TRIANGLES通过连接三个顶点,绘制三角形。



三角形 GL_TRIANGLES


 

环绕问题(winding)

        顶点的指定次序以及方向的组合称为环绕。

        在默认情况下,OpenGL认为逆时针方向环绕的一面是多边形的正面。这个问题十分重要,那是因为我们常常希望为一个多边形的正面和背面分别设置不同的物理特性,如设置不同的颜色和反射属性等。在同一个场景中,使所有的多边形保持环绕方向的一致并使用正面多边形来绘制所有实心物体的外表面是非常重要的。

         如果想改变OpenGL的这个默认行为,可以调用下面这个函数:

         glFrontFace(GL_CW);

         参数GL_CW告诉OpenGL顺时针环绕的多边形将被认为是正面的;

         参数GL_CCW告诉OpenGL逆时针环绕的多边形将被认为是正面的。

 



 

三角形带 GL_TRIANGLE_STRIP

       使用该图元,可以绘制一串相连的三角形,从而节省大量时间。使用三角形带而不是分别指定每个三角形有两个优点:

1、  在用前三个顶点指定了第一个三角形之后,对于接下来的每个三角形,只需要再指定一个顶点。当需要绘制大量的三角形时,采用这种方法可以节省大量的程序代码和数据存储空间。

2、  提高了运算性能并节省了带宽。更少的顶点意味着数据从内存传输到图形卡的速度更快,并且顶点变换的次数也可以更少一些。

 

        注意,三角形带图元的绘制过程,顶点并不是按照它们的指定顺序进行遍历的,这是为了保持每个三角形的环绕方向。




三角形带 GL_TRIANGLE_STRIP



三角形扇 GL_TRIANGLE_FAN

       使用该图元可以创建一组围绕一个中心点的相连三角形。在用前三个顶点指定了第一个三角形后,后续的每个顶点和原点(即中心点)以及自身前驱的那个顶点形成了接下来的那个三角形。



三角形扇 GL_TRIANGLE_FAN



设置多边形的颜色

       颜色是以顶点为单位指定的,而不是以多边形为单位。着色模式决定了多边形是单调着色(最后一个顶点的颜色作为整个多边形的填充颜色),或是渐变着色(根据每个顶点的颜色进行平滑着色)。

       着色模式的设置函数为:

       glShadeModel(GL_FLAT);

       参数GL_FLAT表示使用单调着色;

       参数GL_SMOOTH表示使用平滑着色,根据每个顶点的颜色对三角形进行渐变着色,对相邻顶点的颜色进行匀和。

 

深度测试

       这是一种有效地用于隐藏表面消除的技巧,它的概念十分简单:当一个像素被绘制时,它将被设置一个深度值(称为Z值),以表示它和观察者之间的距离。以后,当这个屏幕位置需要绘制另一个像素时,新像素的Z值就会与原先已经存储的那个像素进行比较。如果新像素的Z值更高,它就更靠近观察者,因此位于以前那个像素的前面;如果新像素的Z值更低,则它必须位于原先那个像素的后面,而不能遮住前面的那个像素。在OpenGL内部,这个任务是通过深度缓冲区实现的,它存储了屏幕上每个像素的深度值。

         为了启用深度测试,需要调用函数:

         glEnable(GL_DEPTH_TEST);

         注意,每次当场景被渲染时,深度缓冲区必须被消除。

 

剔除(CULL)

         这种技巧,用于消除已经知道肯定不会被显示的几何图形。如果不向OpenGL驱动程序和硬件发送这个几何图形,就可以获得显著的性能提升。在这里我们使用背面剔除,它用于消除一个表面的背面。

         通过消除多边形的背面,可以大幅度的减少图像渲染所需要的处理时间。虽然深度测试可以防止物体的内表面被显示,但OpenGL在内部还是要考虑它们,除非显示地告诉它无须如此。

         启用背面剔除,需要调用函数:

         glEnable(GL_CULL_FACE);

 

        下面是程序清单3_8,在3D空间中绘制三角形的代码。我们绘制了一个由三角形组合而成的圆锥,它分为侧面与底面两大部分。该部分代码与绘制其他图元的代码差别主要体现在RenderScene函数上,因此只列出了该函数部分,其余部分代码可参考之前的程序清单。其中使用了深度检测与背面剔除的功能:


/* 程序清单 3-8

 * 2014/4/13

 */

 

// 设置渲染状态

void SetupRC()

{

    // 设置清除窗口的颜色(黑色背景)

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    // 设置绘图颜色为绿色

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

 

    // 把着色模式设置为单调着色

    glShadeModel(GL_FLAT);

    // 把顺时针环绕的多边形设为正面,这与默认是相反的,因为我们使用的是三角形扇

    glFrontFace(GL_CW);

}

 

// 绘制场景(显示回调函数)

void RenderScene()

{

    // 存储坐标和角度

    GLfloat x, y, z, angle;

    // 用于三角形颜色的交替设置

    int iPivot= 1;

 

    // OpenGL命令,清除颜色缓冲区(使用当前设置的颜色)和

    // 深度缓冲区(每次绘制场景必须清除)

    glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT);

 

    // 打开剔除功能(背面剔除,它用于消除一个表面的背面)

    glEnable(GL_CULL_FACE);

    // 打开深度测试

    glEnable(GL_DEPTH_TEST);

 

    // 保存矩阵状态并旋转

    glPushMatrix();

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

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

 

    // 开始绘制图元-三角形扇

    glBegin(GL_TRIANGLE_FAN);

    // 三角形扇的共享顶点,作为圆锥的锥尖,沿Z轴移动,产生一个圆锥

    glVertex3f(0.0f, 0.0f, 75.0f);

    // 绕一个圆循环,指定三角形扇的顶点

    for (angle= 0.0f; angle <= (2.0f * GL_PI + GL_PI / 8.0f); angle += (GL_PI / 8.0f)) {

        // 计算下一个顶点的位置

        x = 50.0f * sin(angle);

        y = 50.0f * cos(angle);

 

        // 交替使用红色和绿色

        if((iPivot % 2) == 0) {

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

        } else{

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

        }

        // 增加基准值,下次改变颜色

        ++iPivot;

 

        // 为三角形扇指定下一个顶点

        glVertex2f(x, y);

    }

 

    glEnd();

 

// 绘制一个新的三角形扇,作为覆盖圆锥的底

    glBegin(GL_TRIANGLE_FAN);

    // 三角形扇的共享顶点,中心位于原点

    glVertex2f(0.0f, 0.0f);

    //

    for (angle= 0.0f; angle < (2.0f * GL_PI + GL_PI / 8.0f); angle += (GL_PI / 8.0f)) {

        // 计算下一个顶点的位置

        x = 50.0f * sin(angle);

        y = 50.0f * cos(angle);

 

        // 交替使用绿色和蓝色

        if((iPivot % 2) == 0) {

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

        } else{

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

        }

        // 增加基准值,下次改变颜色

        ++iPivot;

        // 指定三角形扇的下一个顶点

        glVertex2f(x, y);

    }

    glEnd();

    // 恢复矩阵状态

    glPopMatrix();

    // 刷新绘图命令,此时所有未执行的OpenGL命令被执行

    glutSwapBuffers();

}


        程序运行的结果如图所示,我们可以清楚地看到背面剔除的效果(圆锥底面的正面朝向了圆锥内部):






背面剔除的效果


关闭背面剔除,底面(蓝绿相间部分,看到的是背面)显示出来

0 0
原创粉丝点击