Qt下的OpenGL 程式設計(11)Qt例項hellogl程式碼解析
阿新 • • 發佈:2019-02-08
一、提要
還記得我們在第一篇教程中執行的例子嗎?那是那個可以到處轉的大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幫助。