1. 程式人生 > 實用技巧 >Qt OpenGL 看起來很酷的霧

Qt OpenGL 看起來很酷的霧

這次教程中,我們將在第07課程式碼的基礎上,為木箱的四周填上霧效果。我們將會學習三種不同的霧模式,以及怎麼設定霧的顏色和霧的範圍。雖然這次教程非常簡單,但我們得到的霧效果確實很棒!希望大家能喜歡,當然你也可以把霧效果加到任何一個OpenGL程式中,我相信總能檫出美麗的火花!

程式執行時效果如下:

下面進入教程:

我們這次將在第07課的基礎上修改程式碼,我只會講解有修改的部分,希望大家先找到第07課的程式碼再跟著我一步步走。首先開啟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 QString m_FileName; //圖片的路徑及檔名 26 GLuint m_Texture; //儲存一個紋理 27 28 bool m_Light; //
光源的開/關 29 GLuint m_Fog; //霧的模式 30 31 GLfloat m_xRot; //x旋轉角度 32 GLfloat m_yRot; //y旋轉角度 33 GLfloat m_xSpeed; //x旋轉速度 34 GLfloat m_ySpeed; //y旋轉速度 35 GLfloat m_Deep; //深入螢幕的距離 36 }; 37 38 #endif // MYGLWIDGET_H

我們只是增加了一個變數m_Fog來儲存當前霧的模式(我們會使用三種霧模式),方便我們後面利用鍵盤來控制霧模式的切換。

接下來,我們需要開啟myglwidget.cpp,在建構函式中初始化新增變數,具體程式碼如下:

 1 MyGLWidget::MyGLWidget(QWidget *parent) :
 2     QGLWidget(parent)
 3 {
 4     fullscreen = false;
 5     m_FileName = "D:/QtOpenGL/QtImage/Crate.bmp";        //應根據實際存放圖片的路徑進行修改
 6     m_Light = false;
 7     m_Fog = 0;
 8  
 9     m_xRot = 0.0f;
10     m_yRot = 0.0f;
11     m_xSpeed = 0.0f;
12     m_ySpeed = 0.0f;
13     m_Deep = -5.0f;
14  
15     QTimer *timer = new QTimer(this);                   //建立一個定時器
16     //將定時器的計時訊號與updateGL()繫結
17     connect(timer, SIGNAL(timeout()), this, SLOT(updateGL()));
18     timer->start(10);                                   //以10ms為一個計時週期
19 }

我們給m_Fog賦初始值0,表示第一種霧模式(具體是哪一種下面會講到)。

然後我們需要來修改initializeGL()函式,霧效果的資料初始化都這裡完成的,具體程式碼如下:

 1 void MyGLWidget::initializeGL()                         //此處開始對OpenGL進行所以設定
 2 {
 3     m_Texture = bindTexture(QPixmap(m_FileName));       //載入點陣圖並轉換成紋理
 4     glEnable(GL_TEXTURE_2D);                            //啟用紋理對映
 5  
 6     glClearColor(0.5f, 0.5f, 0.5f, 1.0f);               //設定背景的顏色為霧氣的顏色
 7     glShadeModel(GL_SMOOTH);                            //啟用陰影平滑
 8  
 9     glClearDepth(1.0);                                  //設定深度快取
10     glEnable(GL_DEPTH_TEST);                            //啟用深度測試
11     glDepthFunc(GL_LEQUAL);                             //所作深度測試的型別
12     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);  //告訴系統對透視進行修正
13  
14     //光源部分
15     GLfloat LightAmbient[] = {0.5f, 0.5f, 0.5f, 1.0f};  //環境光引數
16     GLfloat LightDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};  //漫散光引數
17     GLfloat LightPosition[] = {0.0f, 0.0f, 2.0f, 1.0f}; //光源位置
18     glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);     //設定環境光
19     glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);     //設定漫射光
20     glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);   //設定光源位置
21     glEnable(GL_LIGHT1);                                //啟動一號光源
22  
23     //霧部分
24     GLfloat fogColor[] = {0.5f, 0.5f, 0.5f, 1.0f};      //霧的顏色
25     glFogi(GL_FOG_MODE, GL_EXP);                        //設定霧氣的初始模式
26     glFogfv(GL_FOG_COLOR, fogColor);                    //設定霧的顏色
27     glFogf(GL_FOG_DENSITY, 0.35);                       //設定霧的密度
28     glHint(GL_FOG_HINT, GL_DONT_CARE);                  //設定系統如何計算霧氣
29     glFogf(GL_FOG_START, 1.0f);                         //霧的開始位置
30     glFogf(GL_FOG_END, 5.0f);                           //霧的結束位置
31     glEnable(GL_FOG);                                   //啟動霧效果
32 }

首先我們改一下glClearColor()函式的引數,讓清除螢幕的顏色與下面霧的顏色相同。我們在函式末尾加上了我們的霧效果程式碼,首先我們定義霧的顏色(我們定為白色霧,你完全可以根據自己的喜好修改),接著我們設定了霧氣的初始模式為GL_EXP,這是m_Fog等於0時對應的模式,先別急著問為什麼,下面會告訴你答案。

然後我們設定霧的密度,glFogf()函式的第二個引數越大霧會越濃,越小霧會越稀。glHint()函式用於設定修正,我們使用了GL_DONT_CARE因為我們不關心它的值。再接下去兩行設定了霧的起始位置和結束位置,1.0f和5.0f均表示離螢幕的距離,我們完全可以自己根據需要修改這兩個值。最後我們應用glEnable()啟用了霧效果,注意沒有這行是無法產生無效果的。

最後是關於鍵盤控制函式的修改,我們將利用它來控制霧模式的切換,具體程式碼如下:

 1 void MyGLWidget::keyPressEvent(QKeyEvent *event)
 2 {
 3     static GLuint fogMode[] = {GL_EXP, GL_EXP2, GL_LINEAR};
 4  
 5     switch (event->key())
 6     {
 7     case Qt::Key_F1:                                    //F1為全屏和普通屏的切換鍵
 8         fullscreen = !fullscreen;
 9         if (fullscreen)
10         {
11             showFullScreen();
12         }
13         else
14         {
15             showNormal();
16         }
17         break;
18     case Qt::Key_Escape:                                //ESC為退出鍵
19         close();
20         break;
21     case Qt::Key_L:                                     //L為開啟關閉光源的切換鍵
22         m_Light = !m_Light;
23         if (m_Light)
24         {
25             glEnable(GL_LIGHTING);                      //開啟光源
26         }
27         else
28         {
29             glDisable(GL_LIGHTING);                     //關閉光源
30         }
31         break;
32     case Qt::Key_G:                                     //G為霧模式的切換鍵
33         m_Fog++;
34         if (m_Fog == 3)
35         {
36             m_Fog = 0;
37         }
38         glFogi(GL_FOG_MODE, fogMode[m_Fog]);
39         break;
40     case Qt::Key_PageUp:                                //PageUp按下使木箱移向螢幕內部
41         m_Deep -= 0.1f;
42         break;
43     case Qt::Key_PageDown:                              //PageDown按下使木箱移向觀察者
44         m_Deep += 0.1f;
45         break;
46     case Qt::Key_Up:                                    //Up按下減少m_xSpeed
47         m_xSpeed -= 0.1f;
48         break;
49     case Qt::Key_Down:                                  //Down按下增加m_xSpeed
50         m_xSpeed += 0.1f;
51         break;
52     case Qt::Key_Right:                                 //Right按下減少m_ySpeed
53         m_ySpeed -= 0.1f;
54         break;
55     case Qt::Key_Left:                                  //Left按下增加m_ySpeed
56         m_ySpeed += 0.1f;
57         break;
58     }
59 }

注意到我們定義了一個靜態GLuint陣列fogMode[]來儲存我們要切換的霧模式GL_EXP、GL_EXP2、GL_LINEAR三種模式。GL_EXP - 充滿整個螢幕的只是基本渲染的霧,並不是特別像霧;GL_EXP2 - 比GL_EXP更進一步,它也是充滿整個螢幕,但它使螢幕看起來更有深度;GL_LINEAR - 最好的渲染模式,物體淡入淡出的效果更自然(我們可以通過切換鍵比較看看效果就知道了)。由於GL_EXP放在fogMode[0]處,故m_Fog為0時對應的模式是GL_EXP。

每次按下G鍵,我們就讓m_Fog加一,如果加後等於3,就讓它重新回到0,然後呼叫glFogi()函式重新選擇霧模式。

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