1. 程式人生 > 實用技巧 >Qt OpenGL 旋轉

Qt OpenGL 旋轉

這次教程中,我們將在第03課的基礎上,教大家如何旋轉三角形和四邊形。我們將讓三角形沿y軸旋轉,四邊形沿x軸旋轉,最終我們能得到一個三角形和四邊形自動旋轉的場景。

程式執行時效果如下:

下面進入教程:

首先開啟myglwidget.h檔案,我們需要增加兩個變數來控制這兩個物件的旋轉。這兩個變數加在類的私有宣告處,將類宣告更改如下:

 1 #ifndef MYGLWIDGET_H
 2 #define MYGLWIDGET_H
 3  
 4 #include <QWidget>
 5 #include <QGLWidget>
 6  
 7 class MyGLWidget : public
QGLWidget 8 { 9 Q_OBJECT 10 public: 11 explicit MyGLWidget(QWidget *parent = 0); 12 ~MyGLWidget(); 13 14 protected: 15 //對3個純虛擬函式的重定義 16 void initializeGL(); 17 void resizeGL(int w, int h); 18 void paintGL(); 19 20 void keyPressEvent(QKeyEvent *event); //處理鍵盤按下事件
21 22 private: 23 bool fullscreen; //是否全屏顯示 24 25 GLfloat m_rtri; //控制三角形的角度 26 GLfloat m_rquad; //控制四邊形的角度 27 }; 28 29 #endif // MYGLWIDGET_H

我們增加了兩個浮點型別的變數,使得我們能夠非常精確地旋轉物件,你漸漸會發現浮點數是OpenGL程式設計的基礎。新變數中叫做m_rtri的用來旋轉三角形,m_rquad旋轉四邊形。

接下來,我們需要開啟myglwidget.cpp,在建構函式中對兩個新變數進行初始化,這部分很簡單,不作過多解釋,程式碼如下:

1 MyGLWidget::MyGLWidget(QWidget *parent) :
2     QGLWidget(parent)
3 {
4     fullscreen = false;    
5     m_rtri = 0.0f;
6     m_rquad = 0.0f;
7 }

然後進入重點的paintGL()函數了,我們只需在第03課程式碼的基礎上,做一定的修改,就能實現三角形和四邊形的旋轉了。

下面我將重寫整個paintGL()函式,具體程式碼如下:

 1 void MyGLWidget::paintGL()                              //從這裡開始進行所以的繪製
 2 {
 3     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除螢幕和深度快取
 4     glLoadIdentity();                                   //重置當前的模型觀察矩陣
 5  
 6     glTranslatef(-1.5f, 0.0f, -6.0f);                   //左移1.5單位,並移入螢幕6.0單位
 7     glRotatef(m_rtri, 0.0f, 1.0f, 0.0f);                //繞y軸旋轉三角形
 8     glBegin(GL_TRIANGLES);                              //開始繪製三角形
 9         glColor3f(1.0f, 0.0f, 0.0f);                    //設定當前色為紅色
10         glVertex3f(0.0f, 1.0f, 0.0f);                   //上頂點
11         glColor3f(0.0f, 1.0f, 0.0f);                    //設定當前色為綠色
12         glVertex3f(-1.0f, -1.0f, 0.0f);                 //左下
13         glColor3f(0.0f, 0.0f, 1.0f);                    //設定當前色為藍色
14         glVertex3f(1.0f, -1.0f, 0.0f);                  //右下
15     glEnd();                                            //三角形繪製結束
16  
17     glLoadIdentity();                                   //重置模型觀察矩陣
18     glTranslatef(1.5f, 0.0f, -6.0f);                    //右移1.5單位,並移入螢幕6.0單位
19     glRotatef(m_rquad, 1.0f, 0.0f, 0.0f);               //繞x軸旋轉四邊形
20     glColor3f(0.5f, 0.5f, 1.0f);                        //一次性將當前色設定為藍色
21     glBegin(GL_QUADS);                                  //開始繪製四邊形
22         glVertex3f(-1.0f, 1.0f, 0.0f);                  //左上
23         glVertex3f(1.0f, 1.0f, 0.0f);                   //右上
24         glVertex3f(1.0f, -1.0f, 0.0f);                  //左下
25         glVertex3f(-1.0f, -1.0f, 0.0f);                 //右下
26     glEnd();                                            //四邊形繪製結束
27  
28     m_rtri += 0.5f;                                     //增加三角形的旋轉變數
29     m_rquad -= 0.5f;                                    //減少四邊形的旋轉變數
30 }

上面的程式碼繪製三角形時多了一新函式glRotatef(Angle, Xvector, Yvector, Zvector)。該函式負責讓物件繞某個軸旋轉,這個函式有諸多用處。Angle通常是個變數代表物件轉過的角度,後三個引數則共同決定旋轉軸的方向。故(1.0f, 0.0f, 0.0f)、(0.0f, 1.0f, 0.0f)、(0.0f, 0.0f, 1.0f)表示依次繞x、y、z軸旋轉,參照此原理,我們也能實現四邊形的旋轉。

我們會發現畫完三角形後,相比原來的程式碼多了一行glLoadIdentity(),目的是為了重置模型觀察矩陣。如果我們沒有重置,直接呼叫glTranslate的話,會發現可能沒有朝著我們所希望的方向旋轉,這是由於座標軸以前已經旋轉了。所以我們本來要左右移動物件的,可能就變成上下移動了。還不理解的朋友可以試著將glLoadIdentity()試註釋掉之後,看會出現什麼結果。

重置模型觀察矩陣之後,x、y、z軸都復位,我們呼叫glTranslate時只向右移動了1.5單位,而不是之前的3.0單位。因為我們重置場景的時候,焦點又回到了場景的中心,這樣只需右移單位即可。

最後我們通過增加m_rtri和減少m_rquad使得物體自己旋轉起來,我們可以嘗試改變程式碼中的+和-,來體會物件旋轉的方向是如何改變的。並嘗試著將0.5改成4.0,。這個數字越大,物體就轉得越快,這個數字越小,物體轉的就越慢。

至此,我們似乎已經完成了,但是執行程式時發現,三角形和四邊形並沒有自動旋轉起來。這是由於paintGL()被呼叫一次之後,沒有發生其他的事件使得它被自動呼叫。我們可以通過拉伸視窗的大小,發現三角形和四邊形就動起來了,這是由於我們改變了視窗大小,呼叫了reszieGL()之後緊接著呼叫了paintGL()對場景進行重繪。顯然,我們不能一直通過拉伸視窗來實現旋轉,這樣顯得很拙,我們可以在建構函式中利用Qt的定時器事件來控制paintGL()的呼叫。先在myglwidget.cpp中新增標頭檔案#include <QTimer>。建構函式程式碼如下:(具體initializeGL()、reszieGL()、paintGL()的呼叫情況請參見)

 1 MyGLWidget::MyGLWidget(QWidget *parent) :
 2     QGLWidget(parent)
 3 {
 4     fullscreen = false;
 5     m_rtri = 0.0f;
 6     m_rquad = 0.0f;
 7  
 8     QTimer *timer = new QTimer(this);                   //建立一個定時器
 9     //將定時器的計時訊號與updateGL()繫結
10     connect(timer, SIGNAL(timeout()), this, SLOT(updateGL()));
11     timer->start(10);                                   //以10ms為一個計時週期
12 }

這裡將定時器的timeout()訊號與updateGL()槽繫結,每過10ms就會呼叫一次updateGL(),而updateGL()呼叫後會呼叫paintGL()對場景進行重繪,這樣就通過對場景不停地重繪實現物件的旋轉。(對Qt定時器不瞭解的朋友請先百度瞭解下其機制)
現在就可以執行程式看效果了!