这次教程中,我们将在第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()函数重新选择雾模式。
现在就可以运行程序查看效果了!