1. 程式人生 > >【Qt OpenGL教程】08:混合

【Qt OpenGL教程】08:混合

第08課:混合 (參照NeHe)

這次教程中,我們將在紋理對映的基礎上加上混合,使它看起來具有透明的效果,當然解釋它不是那麼容易但程式碼並不難,希望你喜歡它。

OpenGL中的絕大多數特效都與某些型別的(色彩)混合有關。混色的定義為,將某個畫素的顏色和已繪製在螢幕上與其對應的畫素顏色相互結合。至於如何結合這兩種顏色則依賴於顏色的alpha通道的分量值,以及所用的混色函式。Alpha通常是位於顏色值末尾的第4個顏色組成分量,一般都認為Alpha分量代表材料的透明度。也就是說,alpha值為0.0時所代表的材料是完全透明的,alpha值為1.0時所代表的材料則是完全不透明的。

在OpenGL中實現混色的步驟類似於我們以前提到的OpenGL過程,接著設定公式,並在繪製透明物件時關閉寫深度快取。因為我們想在半透明的圖形背後繪製物件,這不是正確的混色方法,但絕大多數時候這種做法在簡單的專案中都工作得很好。正確的混色過程應該是先繪製全部非透明場景之後,再繪製透明的圖形,並且要按照與深度快取相反的次序來繪製

(先畫最遠的物體)。

程式執行時效果如下:


下面進入教程:

我們這次將在第07課的基礎上修改程式碼,首先開啟myglwidget.h檔案,增加一個布林變數m_Blend來記錄是否開啟混合,修改後程式碼如下:

#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;                                //是否全屏顯示

    QString m_FileName;                             //圖片的路徑及檔名
    GLuint m_Texture;                               //儲存一個紋理

    bool m_Light;                                   //光源的開/關
    bool m_Blend;                                   //是否混合
    
    GLfloat m_xRot;                                 //x旋轉角度
    GLfloat m_yRot;                                 //y旋轉角度
    GLfloat m_xSpeed;                               //x旋轉速度
    GLfloat m_ySpeed;                               //y旋轉速度
    GLfloat m_Deep;                                 //深入螢幕的距離
};

#endif // MYGLWIDGET_H

接下來開啟myglwidget.cpp檔案,加上宣告#include <QTimer>,在建構函式中對增加變數進行初始化並更換圖片,使用不同的紋理來繪畫立方體,具體修改後程式碼如下:
MyGLWidget::MyGLWidget(QWidget *parent) :
    QGLWidget(parent)
{
    fullscreen = false;
    m_FileName = "D:/QtOpenGL/QtImage/Glass.bmp";        //應根據實際存放圖片的路徑進行修改
    m_Light = false;
    m_Blend = false;

    m_xRot = 0.0f;
    m_yRot = 0.0f;
    m_xSpeed = 0.0f;
    m_ySpeed = 0.0f;
    m_Deep = -5.0f;

    QTimer *timer = new QTimer(this);                   //建立一個定時器
    //將定時器的計時訊號與updateGL()繫結
    connect(timer, SIGNAL(timeout()), this, SLOT(updateGL()));
    timer->start(10);                                   //以10ms為一個計時週期
}

然後就要進入重點的混合,其他程式碼非常簡單,並不像解釋它時那麼麻煩,只需要對initializeGL()作一定的修改,具體程式碼如下:
void MyGLWidget::initializeGL()                         //此處開始對OpenGL進行所以設定
{
    m_Texture = bindTexture(QPixmap(m_FileName));       //載入點陣圖並轉換成紋理
    glEnable(GL_TEXTURE_2D);                            //啟用紋理對映

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);               //黑色背景
    glShadeModel(GL_SMOOTH);                            //啟用陰影平滑

    glClearDepth(1.0);                                  //設定深度快取
    glEnable(GL_DEPTH_TEST);                            //啟用深度測試
    glDepthFunc(GL_LEQUAL);                             //所作深度測試的型別
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);  //告訴系統對透視進行修正

    //下面是光源部分
    GLfloat LightAmbient[] = {0.5f, 0.5f, 0.5f, 1.0f};  //環境光引數
    GLfloat LightDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};  //漫散光引數
    GLfloat LightPosition[] = {0.0f, 0.0f, 2.0f, 1.0f}; //光源位置
    glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);     //設定環境光
    glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);     //設定漫射光
    glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);   //設定光源位置
    glEnable(GL_LIGHT1);                                //啟動一號光源

    //下面是混合部分
    glColor4f(1.0f, 1.0f, 1.0f, 0.5f);                  //全亮度,50%Alpha混合
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);                  //基於源畫素alpah通道值得半透明混合函式
}
增加了兩行程式碼,第一行以全亮度繪製此物體,並對其進行50%的alpha混合(半透明),當混合選項開啟時,次物體將會產生50%的透明效果。第二行設定所採用的混合型別。看,程式碼真的挺簡單的。

最後是鍵盤控制的程式碼,具體程式碼如下:

void MyGLWidget::keyPressEvent(QKeyEvent *event)
{
    switch (event->key())
    {
    case Qt::Key_F1:                                    //F1為全屏和普通屏的切換鍵
        fullscreen = !fullscreen;
        if (fullscreen)
        {
            showFullScreen();
        }
        else
        {
            showNormal();
        }
        break;
    case Qt::Key_Escape:                                //ESC為退出鍵
        close();
        break;
    case Qt::Key_B:                                     //B為開始關閉混合而對切換鍵
        m_Blend = !m_Blend;
        if (m_Blend)
        {
            glEnable(GL_BLEND);                         //開啟混合
            glDisable(GL_DEPTH_TEST);                   //關閉深度測試
        }
        else
        {
            glDisable(GL_BLEND);                        //關閉混合
            glEnable(GL_DEPTH_TEST);                    //開啟深度測試
        }
        break;
    case Qt::Key_L:                                     //L為開啟關閉光源的切換鍵
        m_Light = !m_Light;
        if (m_Light)
        {
            glEnable(GL_LIGHTING);                      //開啟光源
        }
        else
        {
            glDisable(GL_LIGHTING);                     //關閉光源
        }
        break;
    case Qt::Key_PageUp:                                //PageUp按下使木箱移向螢幕內部
        m_Deep -= 0.1f;
        break;
    case Qt::Key_PageDown:                              //PageDown按下使木箱移向觀察者
        m_Deep += 0.1f;
        break;
    case Qt::Key_Up:                                    //Up按下減少m_xSpeed
        m_xSpeed -= 0.1f;
        break;
    case Qt::Key_Down:                                  //Down按下增加m_xSpeed
        m_xSpeed += 0.1f;
        break;
    case Qt::Key_Right:                                 //Right按下減少m_ySpeed
        m_ySpeed -= 0.1f;
        break;
    case Qt::Key_Left:                                  //Left按下增加m_ySpeed
        m_ySpeed += 0.1f;
        break;
    }
}
當B鍵的控制機制與L鍵相似,但注意到,開啟混合時還要關閉深度測試,關閉混合時還要開啟深度測試,否則將發現立方體有一些面不見了!

現在就可以執行程式看效果了!

相關推薦

Qt OpenGL教程08混合

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

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

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

Qt OpenGL教程04旋轉

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

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教程08.常用的模版標籤和過濾器 視訊學習筆記

繼續搭建blog blog/views.py from django.shortcuts import render_to_response, get_object_or_404 from .models import Blog, BlogType d

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_

全網最全的部落格美化系列教程08.自定義位址列Logo

全網最全的部落格美化系列教程相關文章目錄 【全網最全的部落格美化系列教程】09.新增"擴大/縮小瀏覽區域大小" 按鈕 【全網最全的部落格美化系列教程】10.小火箭置頂特效的實現 【全網最全的部落格美化系列教程】11.滑鼠點選愛心特效的實現 【全網最全的部落格美化系列教程

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