zoukankan      html  css  js  c++  java
  • openGl学习之基本图元

    从本篇開始,会给出一些代码实例,所以要配置好编译环境。

    环境配置:

    vs2012下配置链接http://www.cnblogs.com/dreampursuer/archive/2014/05/27/3754528.html

    vc++6.0下配置链接http://blog.csdn.net/hbuxiaoshe/article/details/5047564


    在给出详细的画图代码之前,先解说一下创建一个openGl程序窗体的初始化,在上一篇文章里已经介绍了,这里再贴一遍。

    void display(void)
    {
        //这是我们自己的画图函数。我们在这里进行详细地绘制。

    } int main(int argc, char** argv) { glutInit(&argc, argv); //对GLUT进行初始化,必须一開始就初始化 glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); //设置显示方式。參数之后再解释 glutInitWindowPosition(100, 100); //设置程序窗体在屏幕中的位置 glutInitWindowSize(400, 400); //设置程序窗体的大小 glutCreateWindow("第一个OpenGL程序"); //给程序窗体加入标题 glutDisplayFunc(&display); //*调用我们自己的画图函数来绘制 glutMainLoop(); //启动消息循环后程序执行起来 return 0; }


    OpenGL的基本图元有点(Point)、线段(Line)、多边形(Ploygon)、三角形(Triangle)、四边形(Quadrangle)。组成关系我想大部分人都可以理解:

      ①无数个“点”的线性排列组成----“线段”

      ②多个“线段”能够围成一个“多边形”

      ③多个“多边形”在三维空间中能够围成“多面体”

    有此,能够看出,点是最主要的图元,其它的图元都是由顶点组合构成的。因此我们从点開始介绍。


    1、点

    在OpenGL中,“点”称为顶点(Vertex),通经常使用一个形如(x, y, z)的三维坐标值表示。

    有时候会採用齐次坐标表示。就是一个形如(x, y, z, w)的四元组,能够这样理解这个四元组。前面的(x,y,z)表示“点”所在的方向。而w表示在该方向上的距离比例。所以(x, y, z, w)表示的实际坐标值就是(x/w, y/w, z/w)坐标点。假设w为0。则表示方向为(x, y, z)的无穷远点;假设w=10,表示取(x,y,z)的十分之中的一个作为坐标点(x/10,y/10,z/10)。

    普通情况 下,OpenGL 中的点将被画成单个的像素。实际上点还能够更小。尽管它可能足够小,但并不会是无穷小,一个像素内能够描绘多个点,取决于对点大小的设定。默认一个点的大小为一个像素。

    当然我们也能够改变点的大小,函数原型为:

    //size 必须大于 0.0f,默认值为 1.0f,单位为“像素”。
    //对于详细的 OpenGL 实现,点的大小都有个限度的,假设设置的 size 超过最大值,则设置可能会有问题,普通情况是不在增大。

    void glPointSize(GLfloat size);

    代码实现画一个点,我们仅仅须要在我们的画图函数中加入例如以下代码就可以:

    void display(void)
    {
        glPointSize(5);//在绘制之前要设置要相关參数,这里设置点的大小为5像素
        glBegin(GL_POINTS);
        {
            glVertex2f(0.0f, 0.0f); //OpenGl内的点是齐次坐标的四元组。缺省的z坐标为0.0f,w为1.0f,所以该点为(0, 0, 0, 1)
            glVertex2f(0.0f, 0.5f); //绘制的第二个点
            glVertex2f(0.5f, 0.25f); //绘制的第三个点
        }
        glEnd();
    
        glFlush();//glFlush,保证前面的OpenGL命令马上运行(而不是让它们在缓冲区中等待)
    }

    须要注意的是:坐标的值默认是1.0为最大,即屏幕边缘,所以假设大于1。则会超出屏幕。这时候除非改变观察点,否则是看不到的。(0,0)表示在屏幕的中间,也就是坐标系原点。

    OpenGL中绘制几何图元,必须使用 glBegain() 和 glEnd() 这一对函数,glBegin() 和 glEnd() 须要成对使用,两者之间是画图语句。

    glBegin()的參数就是须要绘制的图元类型,它决定了在glBegin()和glEnd()之间画图的点将怎样组织成目标图元,如參数为“GL_POINTS”,表示每个点都是独立的,互不相连的。因此也就绘制出了一个个“点”。


    2、线段

    线段是由两个顶点连接起来形成的图元。线段间的连接方式有三种:

    ①独立线段:图元类型參数--GL_LINES

    ②线段间首尾相连但终于不闭合:折线,图元类型參数--GL_LINE_STRIP

    ③线段间首尾相连终于封口闭合:图形。图元类型參数--GL_LINE_LOOP

    相应的图例:

     

    线段代码实例:

    void display(void)
    {
        /*相同用5个点,画出不同类型的线段组合*/
        //独立线段,5个点能画出2条线段
        glBegin(GL_LINES);
        {
            glVertex2f(-0.8f, -0.5f); 
            glVertex2f(-0.5f, -0.5f);
    
            glVertex2f(-0.8f, 0.0f); 
            glVertex2f(-0.5f, 0.0f); 
    
            glVertex2f(-0.8f, 0.5f); //最后的这个点没有与之配对的点。无法连成线段。所以不会被画出来,在独立线段模式下被舍弃
        }
        glEnd();
    
        //连续不闭合折线,5个点能画出4条线段
        glBegin(GL_LINE_STRIP);
        {
            glVertex2f(-0.3f, -0.5f); //起始点
    
            //后面的每个点都会与前一个相连生成一条线段
            glVertex2f(-0.0f, -0.5f);
            glVertex2f(-0.3f, 0.0f); 
            glVertex2f(-0.0f, 0.0f); 
            glVertex2f(-0.3f, 0.5f);
        }
        glEnd();
    
        //连续闭合折线,5个点能画出5条线段
        glBegin(GL_LINE_LOOP);
        {
            glVertex2f(0.2f, -0.5f); //起始点
    
            //后面的每个点都会与前一个相连生成一条线段
            glVertex2f(0.5f, -0.5f);
            glVertex2f(0.2f, 0.0f); 
            glVertex2f(0.5f, 0.0f); 
            //最后一个点不仅与前一个点相连。还与起始点相连,形成闭合
            glVertex2f(0.2f, 0.5f);
        }
        glEnd();
    
        glFlush();//保证前面的OpenGL命令马上运行(而不是让它们在缓冲区中等待)
    }

    程序执行演示样例图:

    相同的。直线能够指定宽度:

    void glLineWidth(GLfloat width); //width表示线宽,单位:像素

    特殊的是线除了直线。还有虚线。能够用虚线连接两个点。

    在绘制虚线之前必须先启动“虚线模式”:glEnable(GL_LINE_STIPPLE);

    虚线有不同的类型。调节函数例如以下:

    /*
            參数pattern是16位二进制数(0或1)。如OxAAAA表示1010101010101010
            从低位開始,每个二进制位代表一个像素。 1表示用当前颜色绘制一个像素。0表示当前不绘制,仅仅移动一个像素位,中间留下一个像素的空白
            factor是用来调节二进制位0和1代表的像素个数。假设factor为2,则表示遇到二进制1的时候用当前颜色绘制两个像素,0移动两个像素不绘制
    */ 
            void glLineStipple(GLint factor,GLushort pattern);

    代码演示样例:

    void display(void)
    {
        //开启虚线模式
        glEnable(GL_LINE_STIPPLE);
        //调节虚线类型參数
        glLineStipple(2,0xAAAA);
        //调节线宽
        glLineWidth(3);
        //绘制一条虚线
        glBegin(GL_LINES);
        {
            glVertex2f(0,0);
            glVertex2f(0.5,0.5);
        }
        glEnd();
    
        glFlush();//保证前面的OpenGL命令马上运行(而不是让它们在缓冲区中等待)
    }

    程序执行演示样例:


    3、多边形

    类似于点组合线段的方式。OpenGL定义的多边形是由多个点连接成线段再围成封闭区域。

    多边形有两种:凸多边形(指多边形随意非相邻的两点的连线位于多边形的内部)和凹多边形,但OpenGL中规定的多边形必须是凸多边形

    但有时须要绘制一些凹多边形,通常解决的办法是对它们进行切割。用多个三角形来组合替代。显然,绘制这些三角形时。有些边不应该进行绘制,否则,多边形内部就会出现多余的线框。OpenGL提供的解决的方法是通过设置边标志命令glEdgeFlag()来控制某些边产生绘制。而另外一些边不产生绘制。这里仅仅需知道有这个工能。详细细节待遇到在研究,接下来看重点。

    (1)连接方式

    <1>按点的定义顺序依次连接:图元类型參数--GL_POLYGON

    <2>从第1个点開始。每三个点一组画一个三角形,三角形之间是独立的:图元类型參数--GL_TRIANGLES

    <3>从第三个点開始,每点与前面的两个点组合画一个三角形,即线性连续三角形串:图元类型參数--GL_TRIANGLE_STRIP

    <4>从第三个点開始,每点与前一个点和第一个点组合画一个三角形。即扇形连续三角形:图元类型參数--GL_TRIANGLE_FAN

    相应的图例:

     

    四边形的绘制模式和三角形类似。

    (2)多边形的正反两面

    多边形为什么会有正反面这一说法呢?举个简单的样例。

    尽管多边形是二维的。可是我们知道三维物体能够理解为多边形围成的,也就是说在三维空间物体上有二维多边形的存在。

    一张“正方形”纸片,假设极限的薄,我们能够觉得是一个多边形(正方形),那么纸仍然会存在两面。纸的正反面。

    更详细一点。假设我们用同大小6张正方形的纸片围成一个正方体,那么正方体的不论什么一个面都是一个多边形,并且这个多边形是有正反面。朝外的你能看到的部分是正面(假设),那么朝内的看不到的那部分就是反面。相同的道理,OpenGL要区分多边形的正反面。

    那么究竟怎么定义正面或者反面呢?

    有一个函数来定义:

    glFrontFace(GL_CCW);//设置点序列逆时针方向围成的多边形为正面
    glFrontFace(GL_CW); //设置点序列顺时针方向围成的多边形为正面

    设置这个的原因是。默认情况下,OpenGL绘制三维物体时两面都会绘制。而实际的时候非常多面我们是看不到的。如物体朝内方向的多边形。另一些物体间遮挡的情况导致有些多边形是不可见的,因此为了提高性能,我们须要剔除这些不必要的绘制。

    glEnable(GL_CULL_FACE); //来启动剔除功能
    glCullFace(); //參数能够是GL_FRONT、GL_BACK、GL_FRONT_AND_BACK,表示剔除多边形的哪种面,设定后该类型的多边形不绘制

    (3)绘制模式

    经常使用的多边形绘制模式有:填充式(默认)轮廓线式顶点式镂空图案填充式

    前三种都是使用glPolygonMode()函数来指定模式,最后一种比較特殊。

    void glPolygonMode(GLenum face,GLenum mode);//该函数要求说明是对多边形哪一个面是定face设置模式

    画一个多边形。设置不同的绘制模式,看一下效果:

    代码:

    void myDisplay(void)
    {
        //设置点的大小,以便easy观察
        glPointSize(5);
    
        //设置正面的绘制模式为:填充式,反面不设定则默觉得填充式
        glPolygonMode(GL_FRONT,GL_FILL);
        glBegin(GL_POLYGON);
        {
            glVertex2f(0,0);
            glVertex2f(0,0.3);
            glVertex2f(-0.3,0.3);
            glVertex2f(-0.3,0);
        }
        glEnd();
    
        //设置正面的绘制模式为:轮廓线式
        glPolygonMode(GL_FRONT,GL_LINE);
        glBegin(GL_POLYGON);
        {
            glVertex2f(0.5,0);
            glVertex2f(0.5,0.3);
            glVertex2f(0.2,0.3);
            glVertex2f(0.2,0);
        }
        glEnd();
    
        //设置正面的绘制模式为:顶点式
        glPolygonMode(GL_FRONT,GL_POINT);
        glBegin(GL_POLYGON);
        {
            glVertex2f(0.9,0);
            glVertex2f(0.9,0.3);
            glVertex2f(0.6,0.3);
            glVertex2f(0.6,0);
        }
        glEnd();
    
        glFlush();
    }

    演示样例图:

    关于最后一种镂空图案样式,有点类似于线段中的虚线,这里仅仅只是是针对多边形内部区域进行像素点的绘制与否。来做镂空效果。

    详细的细节还需查阅资料。

     


    以上为基本图元的知识解说,并给出了针对性的代码实例,在此基础之上会进一步学习更加复杂的图形绘制。

     

     

  • 相关阅读:
    【算法学习笔记】27.动态规划 解题报告 SJTU OJ 1254 传手绢
    【算法学习笔记】26.扫描维护法 解题报告 SJTU OJ 1133 数星星
    【算法学习笔记】25.贪心法 均分纸牌问题的分析
    【算法学习笔记】24.记忆化搜索 解题报告 SJTU OJ 1002 二哥种花生
    【算法学习笔记】23.动态规划 解题报告 SJTU OJ 1280 整装待发
    【算法学习笔记】22.算法设计初步 二分查找 上下界判断
    【算法学习笔记】21.算法设计初步 求第k个数 划分法 快排法
    【算法学习笔记】20.算法设计初步 归并排序 求逆序数
    【算法学习笔记】19.算法设计初步 最大子列和问题的几种方法
    【算法学习笔记】18.暴力求解法06 隐式图搜索2 八数码问题 未启发
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/6863644.html
Copyright © 2011-2022 走看看