Qt下的OpenGL 编程(11)Qt实例hellogl代码解析

来源:互联网 发布:辗转相除法c语言 编辑:程序博客网 时间:2024/06/06 03:23

一、提要


    还记得我们在第一篇教程中运行的例子吗?那是那个可以到处转的大Q,今天我们就来分析一下这个Qt自带的OpenGL例子。

    


二、文件结构
如上图,项目中共有三个类.
glwidget:opengl的渲染窗口,主要负责图形的绘制,同时响应键盘鼠标事件;
window:主窗口类,负责界面的布局,一些信号和槽的实现;
qtlogo:图形类,负责logo的绘制。


三、glwidget类的分析

  首先来看glwidget的头文件:
 
 #ifndef GLWIDGET_H  #define GLWIDGET_H  #include <QGLWidget>  class QtLogo;  //! [0]  class GLWidget : public QGLWidget  {      Q_OBJECT  public:      GLWidget(QWidget *parent = 0);      ~GLWidget();      QSize minimumSizeHint() const;      QSize sizeHint() const;  //! [0]  //! [1]  public slots:      void setXRotation(int angle);      void setYRotation(int angle);      void setZRotation(int angle);  signals:      void xRotationChanged(int angle);      void yRotationChanged(int angle);      void zRotationChanged(int angle);  //! [1]  //! [2]  protected:      void initializeGL();      void paintGL();      void resizeGL(int width, int height);      void mousePressEvent(QMouseEvent *event);      void mouseMoveEvent(QMouseEvent *event);  //! [2]  //! [3]  private:      QtLogo *logo;      int xRot;      int yRot;      int zRot;      QPoint lastPos;      QColor qtGreen;      QColor qtPurple;  };  //! [3]  #endif


       首先是类的构造函数和析构函数,构造函数中可以对成员进行初始化,析够函数
   可以在不再需要这个对象的时候将不再需要的数据删除掉。
        接下来的
        QSize minimumSizeHint() const;
        QSize sizeHint() const;
        用来设置窗口的最小尺寸。


        接下来的三个signal和三个slot分别对应三个方向的旋转:X,Y,Z。


        protected成员中有三个最主要的函数:initializeGL()负责初始化,paintGL()
  负责渲染窗口,resizeGL(int width, int height)在窗口大小变化时调用。后面两个
  则是定义鼠标点击和移动的事件。


        剩下的一些私有变量则是用来记录旋转角度,或是用来初始化logo的变量。


        接下来看一下它的实现:


        
#include <QtGui>        #include <QtOpenGL>        #include <math.h>        #include "glwidget.h"        #include "qtlogo.h"        #ifndef GL_MULTISAMPLE        #define GL_MULTISAMPLE  0x809D        #endif        //! [0]        GLWidget::GLWidget(QWidget *parent)            : QGLWidget(QGLFormat(QGL::SampleBuffers), parent)        {            logo = 0;            xRot = 0;            yRot = 0;            zRot = 0;            qtGreen = QColor::fromCmykF(0.40, 0.0, 1.0, 0.0);            qtPurple = QColor::fromCmykF(0.39, 0.39, 0.0, 0.0);        }        //! [0]        //! [1]        GLWidget::~GLWidget()        {        }        //! [1]        //! [2]        QSize GLWidget::minimumSizeHint() const        {            return QSize(50, 50);        }        //! [2]        //! [3]        QSize GLWidget::sizeHint() const        //! [3] //! [4]        {            return QSize(400, 400);        }        //! [4]        static void qNormalizeAngle(int &angle)        {            while (angle < 0)                angle += 360 * 16;            while (angle > 360 * 16)                angle -= 360 * 16;        }        //! [5]        void GLWidget::setXRotation(int angle)        {            qNormalizeAngle(angle);            if (angle != xRot) {                xRot = angle;                emit xRotationChanged(angle);                updateGL();            }        }        //! [5]        void GLWidget::setYRotation(int angle)        {            qNormalizeAngle(angle);            if (angle != yRot) {                yRot = angle;                emit yRotationChanged(angle);                updateGL();            }        }        void GLWidget::setZRotation(int angle)        {            qNormalizeAngle(angle);            if (angle != zRot) {                zRot = angle;                emit zRotationChanged(angle);                updateGL();            }        }        //! [6]        void GLWidget::initializeGL()        {            qglClearColor(qtPurple.dark());            logo = new QtLogo(this, 64);            logo->setColor(qtGreen.dark());            glEnable(GL_DEPTH_TEST);            glEnable(GL_CULL_FACE);            glShadeModel(GL_SMOOTH);            glEnable(GL_LIGHTING);            glEnable(GL_LIGHT0);            glEnable(GL_MULTISAMPLE);            static GLfloat lightPosition[4] = { 0.5, 5.0, 7.0, 1.0 };            glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);        }        //! [6]        //! [7]        void GLWidget::paintGL()        {            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);            glLoadIdentity();            glTranslatef(0.0, 0.0, -10.0);            glRotatef(xRot / 16.0, 1.0, 0.0, 0.0);            glRotatef(yRot / 16.0, 0.0, 1.0, 0.0);            glRotatef(zRot / 16.0, 0.0, 0.0, 1.0);            logo->draw();        }        //! [7]        //! [8]        void GLWidget::resizeGL(int width, int height)        {            int side = qMin(width, height);            glViewport((width - side) / 2, (height - side) / 2, side, side);            glMatrixMode(GL_PROJECTION);            glLoadIdentity();        #ifdef QT_OPENGL_ES_1            glOrthof(-0.5, +0.5, -0.5, +0.5, 4.0, 15.0);        #else            glOrtho(-0.5, +0.5, -0.5, +0.5, 4.0, 15.0);        #endif            glMatrixMode(GL_MODELVIEW);        }        //! [8]        //! [9]        void GLWidget::mousePressEvent(QMouseEvent *event)        {            lastPos = event->pos();        }        //! [9]        //! [10]        void GLWidget::mouseMoveEvent(QMouseEvent *event)        {            int dx = event->x() - lastPos.x();            int dy = event->y() - lastPos.y();            if (event->buttons() & Qt::LeftButton) {                setXRotation(xRot + 8 * dy);                setYRotation(yRot + 8 * dx);            } else if (event->buttons() & Qt::RightButton) {                setXRotation(xRot + 8 * dy);                setZRotation(zRot + 8 * dx);            }            lastPos = event->pos();        }



         构造函数中首先对几个私有变量进行了初始化,析够函数中什么都没有做(自动回收?),
接下来的qNormalizeAngle函数,是用于纠正角度的,因为在旋转了很多圈之后,角度会变得很大,需要对其进行纠正。
    接下来是对三个槽函数的定义,在调用之前都要对角度进行纠正,然后改变相应的角度的值,接着发出角度改变的信号。
这个信号最后是和window类中的控制滑动条的槽链接起来了,当logo发生旋转的时候,就会把旋转的角度告诉给window,然后
window的槽执行相应的语句,滑动条位置发生改变。
    相反,当window的滑动条数值发生改变的时候,也会发出相应的信号给glwiget的三个槽函数,然后logo执行旋转。


    initializeGL中对logo进行了初始化,还定义了灯光等的参数,比较好理解。


    paintGL中我们主要来看一下坐标的变换:首先是把绘制点移到了(0,0,-10)的
位置,然后绕三个轴进行旋转,做后将logo绘制出来(logo的绘制还是有点麻烦,有兴趣的同学可以慢慢研究一下qtlogo类)。


    mouseMoveEvent则是对鼠标拖动的响应,左键拖动和右键拖动分别绕不同的方向旋转。
调用的是之前定义的set槽函数。
    所以这个类的槽函数有两个作用:1.当作一般的函数;2.响应某个信号。
三、参考
    QT帮助。
	
				
		
原创粉丝点击