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()函式重新選擇霧模式。
現在就可以執行程式檢視效果了!