您的位置:首页 > 编程语言 > Qt开发

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

2012-08-28 15:24 549 查看

一、提要

还记得我们在第一篇教程中运行的例子吗?那是那个可以到处转的大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帮助。
  

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息