• 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()函数重新选择雾模式。

    现在就可以运行程序查看效果了!

  • 相关阅读:
    uniapp中的跳转传参
    图解排序算法(三)之堆排序
    serverlesss
    kvm
    用户态和内核态的理解和区别
    MySQL优化十大技巧
    不懂数据库索引的底层原理?那是因为你心里没点b树
    让你的 Linux 命令骚起来
    史上最简约的vi教程
    mysql 四种隔离级别
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/14048424.html
Copyright © 2020-2023  润新知