1. 程式人生 > >【Qt OpenGL教程】04:旋轉

【Qt OpenGL教程】04:旋轉

第04課:旋轉 (參照NeHe)

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

程式執行時效果如下:


下面進入教程:

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

#ifndef MYGLWIDGET_H
#define MYGLWIDGET_H

#include <QWidget>
#include <QGLWidget>

class MyGLWidget : public QGLWidget
{
    Q_OBJECT
public:
    explicit MyGLWidget(QWidget *parent = 0);
    ~MyGLWidget();

protected:
    //對3個純虛擬函式的重定義
    void initializeGL();
    void resizeGL(int w, int h);
    void paintGL();

    void keyPressEvent(QKeyEvent *event);           //處理鍵盤按下事件

private:
    bool fullscreen;                                //是否全屏顯示
    
    GLfloat m_rtri;                                 //控制三角形的角度
    GLfloat m_rquad;                                //控制四邊形的角度
};

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

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

MyGLWidget::MyGLWidget(QWidget *parent) :
    QGLWidget(parent)
{
    fullscreen = false;    
    m_rtri = 0.0f;
    m_rquad = 0.0f;
}

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

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

void MyGLWidget::paintGL()                              //從這裡開始進行所以的繪製
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除螢幕和深度快取
    glLoadIdentity();                                   //重置當前的模型觀察矩陣

    glTranslatef(-1.5f, 0.0f, -6.0f);                   //左移1.5單位,並移入螢幕6.0單位
    glRotatef(m_rtri, 0.0f, 1.0f, 0.0f);                //繞y軸旋轉三角形
    glBegin(GL_TRIANGLES);                              //開始繪製三角形
        glColor3f(1.0f, 0.0f, 0.0f);                    //設定當前色為紅色
        glVertex3f(0.0f, 1.0f, 0.0f);                   //上頂點
        glColor3f(0.0f, 1.0f, 0.0f);                    //設定當前色為綠色
        glVertex3f(-1.0f, -1.0f, 0.0f);                 //左下
        glColor3f(0.0f, 0.0f, 1.0f);                    //設定當前色為藍色
        glVertex3f(1.0f, -1.0f, 0.0f);                  //右下
    glEnd();                                            //三角形繪製結束

    glLoadIdentity();                                   //重置模型觀察矩陣
    glTranslatef(1.5f, 0.0f, -6.0f);                    //右移1.5單位,並移入螢幕6.0單位
    glRotatef(m_rquad, 1.0f, 0.0f, 0.0f);               //繞x軸旋轉四邊形
    glColor3f(0.5f, 0.5f, 1.0f);                        //一次性將當前色設定為藍色
    glBegin(GL_QUADS);                                  //開始繪製四邊形
        glVertex3f(-1.0f, 1.0f, 0.0f);                  //左上
        glVertex3f(1.0f, 1.0f, 0.0f);                   //右上
        glVertex3f(1.0f, -1.0f, 0.0f);                  //左下
        glVertex3f(-1.0f, -1.0f, 0.0f);                 //右下
    glEnd();                                            //四邊形繪製結束

    m_rtri += 0.5f;                                     //增加三角形的旋轉變數
    m_rquad -= 0.5f;                                    //減少四邊形的旋轉變數
}
上面的程式碼繪製三角形時多了一新函式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()的呼叫情況請參見)

MyGLWidget::MyGLWidget(QWidget *parent) :
    QGLWidget(parent)
{
    fullscreen = false;
    m_rtri = 0.0f;
    m_rquad = 0.0f;

    QTimer *timer = new QTimer(this);                   //建立一個定時器
    //將定時器的計時訊號與updateGL()繫結
    connect(timer, SIGNAL(timeout()), this, SLOT(updateGL()));
    timer->start(10);                                   //以10ms為一個計時週期
}
這裡將定時器的timeout()訊號與updateGL()槽繫結,每過10ms就會呼叫一次updateGL(),而updateGL()呼叫後會呼叫paintGL()對場景進行重繪,這樣就通過對場景不停地重繪實現物件的旋轉。(對Qt定時器不瞭解的朋友請先百度瞭解下其機制)
現在就可以執行程式看效果了!

相關推薦

Qt OpenGL教程04旋轉

第04課:旋轉 (參照NeHe) 這次教程中,我們將在第03課的基礎上,教大家如何旋轉三角形和四邊形。我們將讓三角形沿y軸旋轉,四邊形沿x軸旋轉,最終我們能得到一個三角形和四邊形自動旋轉的場景。 程式執行時效果如下: 下面進入教程: 首先開啟myglwidget.h

Qt OpenGL教程25變形和從檔案中載入3D物體

第25課:變形和從檔案中載入3D物體 (參照NeHe) 這次教程中,我們將學會如何從檔案中載入3D模型,並且平滑的從一個模型變形為另一個模型。在這一課裡,我們將介紹如何實現模型的變形過程,這將會是效果很棒的一課! 程式執行時效果如下: 下面進入教程: 我們這次將在第

Qt OpenGL教程08混合

第08課:混合 (參照NeHe) 這次教程中,我們將在紋理對映的基礎上加上混合,使它看起來具有透明的效果,當然解釋它不是那麼容易但程式碼並不難,希望你喜歡它。 OpenGL中的絕大多數特效都與某些型別的(色彩)混合有關。混色的定義為,將某個畫素的顏色和已繪製在螢幕上與其對應

Qt OpenGL教程06紋理對映

void MyGLWidget::paintGL() //從這裡開始進行所以的繪製 { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除螢幕和深度快取 glLoadIden

Qt OpenGL教程01建立一個OpenGL視窗

void MyGLWidget::resizeGL(int w, int h) //重置OpenGL視窗的大小 { glViewport(0, 0, (GLint)w, (GLint)h); //重置當前的視口 glMatrixMod

Qt OpenGL教程29Blitter函式

第29課:Blitter函式 (參照NeHe) 這次教程中,我們將介紹類似於DirectDraw的blit(其實blit函式在許多繪相簿都有),我們將用程式碼自己來實現它。它的作用非常簡單,就是把一塊紋理的貼到另一塊紋理上。想想,有了這個函式,我們就可以自由拼接紋理了,是不

Qt OpenGL教程28貝塞爾曲面

第28課:貝塞爾曲面 (參照NeHe) 這次教程中,我們將介紹貝塞爾曲面,因此這是關於數學運算的一課(這導致很不好講),來吧,相信你能搞定它的!這一課中,我們並不是要做一個完整的貝塞爾曲面庫(庫的話OpenGL已經完成了),而是一個展示概念的程式,來讓你熟悉曲面是怎麼計算實

Django2.0Django2.0教程04.使用模版顯示內容 視訊學習筆記

檢視文章頁面:唯一標示id article/migrations/0001_initial.py的內容如下: # Generated by Django 2.0.5 on 2018-05-11 06:54 from django.db import m

Qt OpenGLQt Creator中的3D繪圖及動畫教程

Qt Creator中的3D繪圖及動畫教程(參照NeHe) 剛剛學習了Qt Creator,發現Qt提供了QtOpenGL模組,對OpenGL做了不錯的封裝,這使得我們可以很輕鬆地在Qt程式中使用OpenGL進行繪圖渲染。雖然裡面還是由不少專業的解釋照搬原文的,但還是加入了

Unity3D基礎教程給初學者看的Unity教程(零)如何學習Unity3D

cos 詳解 component lock index unity3d遊戲 design 技術棧 log 【Unity3D基礎教程】給初學者看的Unity教程(零):如何學習Unity3D http://www.cnblogs.com/neverdie/p/How_To_

BBC micro:bit基礎教程04-micro:bit讀取光敏電阻

www. inf 訪問 主板 bit 讀取 藍色 電路 問題 【所需材料】 BBC micro:bit 主板 x 1 Micro USB 線 x 1 能容納2節7號(AAA)電池的電池盒 x 1 7號(AAA)電池 x 2 光敏電阻 x 1 10kΩ 電阻 x 1 鱷

Qt學習筆記Qt編譯好之後執行程式時提示程式異常結束。The process was ended forcefully. ....exe crashed.

最近在Qt結合imagingsource相機使用時編譯能夠通過,但是一直無法執行出現如下提示 此時進入Debug模式也無法進入一直提示出錯,在網上搜尋了很多資料一般的結論是少了一些配置,後來順著這個思路,折騰了兩三天發現是沒有加入DLL。因為其他的工業相機一般安裝sdk的

Unity3D基礎教程給初學者看的Unity教程(六)理解Unity的新GUI系統(UGUI)

理解UGUI的基礎架構 UGUI是Unity在4.6中引入的新的GUI系統,與傳統的中介軟體NGUI相比,這套新GUI系統有幾個核心亮點: 放棄了Atlas的概念,使用Packing Tag的方式來進行圖集的規劃 放棄了depth來確定UI顯示層級的概念,使用Hierarchy的SiblingIndex

Unity3D基礎教程給初學者看的Unity教程(二)所有指令碼元件的基類 -- MonoBehaviour的前世今生

引子 上一次我們講了GameObject,Compoent,Time,Input,Physics,其中Time,Input,Physics都是Unity中的全域性變數。GameObject是遊戲中的基本物件。GameObject是由Component組合而成的,GameObject本身必須有

Unity3D基礎教程給初學者看的Unity教程(五)詳解Unity3D中的協程(Coroutine)

為什麼需要協程 在遊戲中有許多過程(Process)需要花費多個邏輯幀去計算。 你會遇到“密集”的流程,比如說尋路,尋路計算量非常大,所以我們通常會把它分割到不同的邏輯幀去進行計算,以免影響遊戲的幀率。 你會遇到“稀疏”的流程,比如說遊戲中的觸發器,這種觸發器大多數時候什麼也不做,但

Unity3D基礎教程給初學者看的Unity教程(三)通過製作Flappy Bird瞭解Native 2D中的Sprite,Animation

引子 上一次我們講了MonoBehaviour的前世今生,瞭解了遊戲中的每一個GameObjec都是由指令碼控制的,這一次我們開始將Unity中Native 2D中的Sprite,並且使用Animation來讓Sprite動起來。 在接下來的幾篇部落格裡,我會通過做一個Flappy Bird來講解

Unity3D基礎教程給初學者看的Unity教程(四)通過製作Flappy Bird瞭解Native 2D中的RigidBody2D和Collider2D

引子 認識RigidBody 當RigidBody2D的質量屬性被設定為0時,剛體的質量變為無限大,此時剛體相當於靜態剛體,永遠一動不動。但是在Unity中你是無法把一個RigidBody2D的質量設定為0的,所以,當你想建立一個靜態剛體時,只需要建立碰撞器,而不需要建立RigidBo

Unity3D基礎教程給初學者看的Unity教程(七)在Unity中構建健壯的單例模式(Singleton)

該部落格中的程式碼均出自我的開源專案 : 迷你微信 為什麼需要單例模式 遊戲中需要單例有以下幾個原因: 我們需要在遊戲開始前和結束前做一些操作,比如網路的連結和斷開,資源的載入和解除安裝,我們一般會把這部分邏輯放在單例裡。 單例可以控制初始化和銷燬順序,而靜態變數和場景中的GameObject都無法控制

Unity3D基礎教程給初學者看的Unity教程(一)GameObject,Compoent,Time,Input,Physics

Unity3D重要模組的類圖 最近剛剛完成了一個我個人比較滿意的小專案:【深入Cocos2d-x】使用MVC架構搭建遊戲Four,在這個遊戲中,我使用了自己搭建的MVC架構來製作一個遊戲,做到了比較好的SoC(關注點分離)。但是苦於Cocos2d-x沒有一個比較完善的編輯器,所以我開始學習另一個非常流行

Django2.0Django2.0教程02.入門儀式Hello World 視訊學習筆記

進入到需要放置專案的路徑,使用如下命令建立專案: $ django-admin startproject mysite 這裡,mysite為專案名稱,也可以是其他的名字。進入到mysite目錄之後,可以看到目錄結構如下: . ├── mana