zoukankan      html  css  js  c++  java
  • OpenGL_Qt学习笔记之_02(绘制简单平面几何图形)

     

    本文来讲讲怎样使用opengl来画平面几何图形,这一节本来是很简单的,因为某些问题都弄大半天了。当然,这还是按照NeHe的教程来的学习的。

    这次实现的功能是在窗口中画一个三角形,一个矩形,一个圆形。

     

    首先来简单的看一下opengl中的基本坐标规则,如下图所示:

       

    假设左下角那个点是人的眼睛观察的位置,则向左为x正方向,向上为y的正方向(这点与opencv中不同),向里为z的正方向。

     

    下面来看看怎么绘制平面几何图形。在设置好需要画的几何图形的属性后,比如颜色信息,就以glBegin()开始,以glEnd()结束,glBegin()中的参数为所画几何图形的类型,比如说GL_ TRIANGLES代表三角形,GL_QUADS为矩形等等。

    glBegin()glEnd()之间是放的点,这里是三维的点,这些点是对应所画矩形的类型的。

    画圆的话稍微麻烦一点,因为opengl中没有直接对应的类型,一般都是采用三角形来逼近,其它很多几何图形也是类似的。在用三角形逼近时,是用的画连续三角形,一般有2种类型。GL_TRIANGLE_STRIPGL_TRIANGLE_PAN,2者的区别首先来看个示意图:

       

    如果给定有顺序的点v0,v1,v2,v3,v4,v5,则采用GL_TRIANGLE_STRIP模式时,所画的连续三角形应该依次为:(v0,v1,v2),(v1, v2, v3), (v2, v3, v4),(v3, v4, v5);如果采用的是GL_TRIANGLE_PAN模式,则第一个点是固定的,且后面每次都要跳一个顶点,所以它的结果为(v0, v1, v2), (v0, v2, v3), (v0, v3, v4),(v0, v4, v5)

    因此我这里要画圆盘的话,就采用的GL_TRIANGLE_PAN模式了,大家可以手动画一下就知道,具体可以参考后面给出的代码。

     

    每次绘一个几何图形,都会移动当前的焦点,采用的函数是glTranslatef,而网上的教程给该函数的参数时,都是类似这样的glTranslatef(-1.5f, 0.0f, -6.0f);NeHe的教程中也是一样,他的解释是移动多少个单位,比如说-1.5f就是向左移动1.5个单位,我一开始也在程序中这么弄,结果调试了4个多小时,就是不显示三角形,在网上找了很多方法,都试过了还不行。以为在昨天的教程OpenGL_Qt学习笔记之_01(创建一个OpenGL窗口) 中我提到过新版本的Qt不支持gluPerspective等函数(今天查资料发现gluPerspective函数原来是opengl新版本就没有支持了,所以在Qt的新版本中当然也不支持了),而在网上所有的教程中的resizeGL()函数中都使用了这个函数,所以怀疑是这个问题,但是我看了Qt自带的那么多samples没有用这个函数但都可以编译运行,所以应该是不相关的。后面中午在食堂吃饭时突然觉得我是不是把焦点移得太远了,以至于在屏幕中显示不到,快速吃完饭后回到宿舍把函数改为glTranslatef(-0.15f, 0.0f, 0.0f); 都缩小10倍后就能看到三角形了。

    经过一些测试,发现Qt中的opengl的屏幕长和宽都只有2个单位的长度,所以需要显示的区域只能是-1+1. 但我看网上很多用Qt写的网友,都是glTranslatef(-1.5f, 0.0f, -6.0f);这样写的,他们的屏幕长度肯定不止这么多,问题出现在哪呢?暂时还没弄明白,不会是gluPerspective()函数没设置吧?有知道的网友可以提供下信息,谢谢!

     

    下面来看看实验运行的效果:

       

    那个圆看起来不是很圆,发现是显示它的窗口本身是个长方形,不是正方形,后面把窗口拖动近似为正方形后,其运行结果如下:

      

      但是个人感觉这个圆的显示应该独立于窗口的形状才行,大家有什么可行的方法么?

     

    程序主要代码和注释如下(附录有工程code下载地址):

    本来只需要给出paintGL()函数代码就可以的,因为其它代码和上篇文章的一样,但是我这里有几个问题没弄懂,所以都贴出来让大家帮忙看看。

    glwidget.h:

    #ifndef GLWIDGET_H
    #define GLWIDGET_H
    
    #include <QtOpenGL>
    #include <QWidget>
    
    namespace Ui {
    class GLWidget;
    }
    
    class GLWidget : public QGLWidget
    {
        Q_OBJECT
        
    public:
        explicit GLWidget(QGLWidget *parent = 0);
        ~GLWidget();
    
    protected:
        void initializeGL();
        void paintGL();
        void resizeGL(int width, int height);
        void keyPressEvent(QKeyEvent *e);
        bool fullscreen;
        
    private:
        Ui::GLWidget *ui;
    };
    
    #endif // GLWIDGET_H

     

    glwidget.cpp:

    #include "glwidget.h"
    #include "ui_glwidget.h"
    
    #include <QtGui>
    #include <QtCore>
    #include <QtOpenGL>
    
    #ifndef GL_MULTISAMPLE
    #define GL_MULTISAMPLE  0x809D
    #endif
    
    #define GL_PI 3.1415926
    #define GL_RADIUX  0.2f
    
    GLWidget::GLWidget(QGLWidget *parent) :
        QGLWidget(parent),
        ui(new Ui::GLWidget)
    {
      //  setWindowTitle("The Opengl for Qt Framework");
        ui->setupUi(this);
        fullscreen = false;
    
    }
    
    //这是对虚函数,这里是重写该函数
    void GLWidget::initializeGL()
    {
        setGeometry(300, 150, 640, 480);//设置窗口初始位置和大小
        glShadeModel(GL_SMOOTH);//设置阴影平滑模式
        glClearColor(0.0, 0.0, 0.0, 0.0);//改变窗口的背景颜色,不过我这里貌似设置后并没有什么效果
        glClearDepth(1.0);//设置深度缓存
        glEnable(GL_DEPTH_TEST);//允许深度测试
        glDepthFunc(GL_LEQUAL);//设置深度测试类型
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);//进行透视校正
    }
    
    void GLWidget::paintGL()
    {
    
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //glClear()函数在这里就是对initializeGL()函数
                                                            //中设置的颜色和缓存深度等起作用
        glLoadIdentity();//重置当前的模型观察矩阵,该句执行完后,将焦点移动到了屏幕的中心
    
        /*下面几句代码是用来画三角形的,以glBegin()开始,glEnd()结束;glVertex3f为给定一个3维的顶点,坐标值为浮点型*/
        //  glTranslatef(-1.5f, 0.0f, -6.0f);//首先移动当前焦点位置
        glTranslatef(-0.3, 0.3, -0.6);
        glColor3f(1.0f, 0.0f, 0.0f);
      //  glDisable(GL_TEXTURE_2D);
        glBegin(GL_TRIANGLES);//GL_TRIANGLES代表为画三角形
        glVertex3f(0.0f, 0.2f, 0.0f);//上顶点坐标
        glVertex3f(-0.2f, -0.2f, 0.0f);//左下角坐标
        glVertex3f(0.2f, -0.2f, 0.0f);//右下角坐标
        glEnd();//结束画完
    
        glLoadIdentity();//重新焦点定位,同样是屏幕的中心
        glTranslatef(0.3f,0.3f,0.0f); // 向x轴正方向移动0.3个单位
        glColor3f(0.0f,1.0f,0.0f);//颜色设置放在这个地方,对下面的顶点设置都是有效的
    
        /*下面开始绘制四边形*/
        glBegin(GL_QUADS);
        glVertex3f(-0.2f, 0.2f, 0.0f); // 左上顶点
        glVertex3f( 0.2f, 0.2f, 0.0f); // 右上顶点
        glVertex3f( 0.2f, -0.2f, 0.0f); // 右下顶点
        glVertex3f(-0.2f, -0.2f, 0.0f); // 左下顶点
        glEnd(); // 四边形绘制结束
    
        glLoadIdentity();
        glTranslatef(0.0f, -0.3f, 0.0f);
        glColor3f(0.0f, 0.0f, 1.0f);
    
        /*用连续的点来逼近圆这里是画的一个圆周*/
    //    GLfloat x, y, angle;
    //    glBegin(GL_POINTS);
    //    for(angle = 0; angle <2*GL_PI; angle +=0.001)
    //    {
    //        x = GL_RADIUX*sin(angle);
    //        y = GL_RADIUX*cos(angle);
    //        glVertex3d(x, y, 0.0);
    //    }
    //    glEnd();
    //    glPopMatrix();
    
        /*这里用连续的三角形面积来逼近圆的面积实现圆周的画法*/
        GLint circle_points = 100, i = 0;
        glBegin(GL_TRIANGLE_FAN);
        for(int i = 0; i < circle_points; i++ )
        {
            double angle = 2*GL_PI*i/circle_points;
            glVertex3d(0.2*cos(angle), 0.2*sin(angle), 0);
        }
        glEnd();
    
    }
    
    //该程序是设置opengl场景透视图,程序中至少被执行一次(程序启动时).
    void GLWidget::resizeGL(int width, int height)
    {
        if(0 == height)
            height = 1;//防止一条边为0
        glViewport(0, 0, (GLint)width, (GLint)height);//重置当前视口,本身不是重置窗口的,只不过是这里被Qt给封装好了
        glMatrixMode(GL_PROJECTION);//选择投影矩阵
        glLoadIdentity();//重置选择好的投影矩阵
       // gluPerspective(45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0);//建立透视投影矩阵
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    
    
    }
    void GLWidget::keyPressEvent(QKeyEvent *e)
    {
        switch(e->key())
        {
            //F1键为全屏和普通屏显示切换键
            case Qt::Key_F1:
                fullscreen = !fullscreen;
                if(fullscreen)
                    showFullScreen();
                else
                {
                    setGeometry(300, 150, 640, 480);
                    showNormal();
                }
                updateGL();
                break;
            //Ese为退出程序键
            case Qt::Key_Escape:
                close();
        }
    }
    
    GLWidget::~GLWidget()
    {
        delete ui;
    }

    main.cpp:

    #include <QApplication>
    #include "glwidget.h"
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        GLWidget w;
        w.show();
        
        return a.exec();
    }

      总结:通过本次实验,初步了解了在opengl中怎么绘制简单的平面几何图形。

     

     

      参考资料:

      http://nehe.gamedev.net/ 

      http://www.owlei.com/DancingWind/

      http://blog.csdn.net/qp120291570/article/details/7853513

     

     

      附录:

    实验工程code下载地址

     

     

     

     

     

  • 相关阅读:
    线性代数:矩阵行列式
    线性代数:逆变换
    线性代数:线性变换
    线性代数:零空间
    线性代数:向量乘法
    线性代数基础:向量组合
    线性代基础理论:向量
    线性代基础理论:矩阵
    SpringBoot 消费NSQ消息
    将Oracle中的数据放入elasticsearch
  • 原文地址:https://www.cnblogs.com/tornadomeet/p/2652592.html
Copyright © 2011-2022 走看看