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

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

2012-12-15 20:41 411 查看
一、提要

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



二、文件结构

如上图,项目中共有三个类.

glwidget:opengl的渲染窗口,主要负责图形的绘制,同时响应键盘鼠标事件;

window:主窗口类,负责界面的布局,一些信号和槽的实现;

qtlogo:图形类,负责logo的绘制。



三、glwidget类的分析


首先来看glwidget的头文件:

[cpp] view
plaincopy

#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的变量。

接下来看一下它的实现:

[cpp] view
plaincopy

#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帮助。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: