• Qt OpenGL 混合


    这次教程中,我们将在纹理映射的基础上加上混合,使它看起来具有透明的效果,当然解释它不是那么容易但代码并不难,希望你喜欢它。

    OpenGL中的绝大多数特效都与某些类型的(色彩)混合有关。混色的定义为,将某个像素的颜色和已绘制在屏幕上与其对应的像素颜色相互结合。至于如何结合这两种颜色则依赖于颜色的alpha通道的分量值,以及所用的混色函数。Alpha通常是位于颜色值末尾的第4个颜色组成分量,一般都认为Alpha分量代表材料的透明度。也就是说,alpha值为0.0时所代表的材料是完全透明的,alpha值为1.0时所代表的材料则是完全不透明的。

    在OpenGL中实现混色的步骤类似于我们以前提到的OpenGL过程,接着设置公式,并在绘制透明对象时关闭写深度缓存。因为我们想在半透明的图形背后绘制对象,这不是正确的混色方法,但绝大多数时候这种做法在简单的项目中都工作得很好。正确的混色过程应该是先绘制全部非透明场景之后,再绘制透明的图形,并且要按照与深度缓存相反的次序来绘制(先画最远的物体)。

    程序运行时效果如下:

    下面进入教程:

    我们这次将在第07课的基础上修改代码,首先打开myglwidget.h文件,增加一个布尔变量m_Blend来记录是否开启混合,修改后代码如下:

     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     bool m_Blend;                                   //是否混合
    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

    接下来打开myglwidget.cpp文件,加上声明#include <QTimer>,在构造函数中对增加变量进行初始化并更换图片,使用不同的纹理来绘画立方体,具体修改后代码如下:

     1 MyGLWidget::MyGLWidget(QWidget *parent) :
     2     QGLWidget(parent)
     3 {
     4     fullscreen = false;
     5     m_FileName = "D:/QtOpenGL/QtImage/Glass.bmp";        //应根据实际存放图片的路径进行修改
     6     m_Light = false;
     7     m_Blend = false;
     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 }

    然后就要进入重点的混合,其他代码非常简单,并不像解释它时那么麻烦,只需要对initializeGL()作一定的修改,具体代码如下:

     1 void MyGLWidget::initializeGL()                         //此处开始对OpenGL进行所以设置
     2 {
     3     m_Texture = bindTexture(QPixmap(m_FileName));       //载入位图并转换成纹理
     4     glEnable(GL_TEXTURE_2D);                            //启用纹理映射
     5  
     6     glClearColor(0.0f, 0.0f, 0.0f, 0.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     glColor4f(1.0f, 1.0f, 1.0f, 0.5f);                  //全亮度,50%Alpha混合
    25     glBlendFunc(GL_SRC_ALPHA, GL_ONE);                  //基于源像素alpah通道值得半透明混合函数
    26 }

    增加了两行代码,第一行以全亮度绘制此物体,并对其进行50%的alpha混合(半透明),当混合选项开启时,次物体将会产生50%的透明效果。第二行设置所采用的混合类型。看,代码真的挺简单的。

    最后是键盘控制的代码,具体代码如下:

     1 void MyGLWidget::keyPressEvent(QKeyEvent *event)
     2 {
     3     switch (event->key())
     4     {
     5     case Qt::Key_F1:                                    //F1为全屏和普通屏的切换键
     6         fullscreen = !fullscreen;
     7         if (fullscreen)
     8         {
     9             showFullScreen();
    10         }
    11         else
    12         {
    13             showNormal();
    14         }
    15         break;
    16     case Qt::Key_Escape:                                //ESC为退出键
    17         close();
    18         break;
    19     case Qt::Key_B:                                     //B为开始关闭混合而对切换键
    20         m_Blend = !m_Blend;
    21         if (m_Blend)
    22         {
    23             glEnable(GL_BLEND);                         //开启混合
    24             glDisable(GL_DEPTH_TEST);                   //关闭深度测试
    25         }
    26         else
    27         {
    28             glDisable(GL_BLEND);                        //关闭混合
    29             glEnable(GL_DEPTH_TEST);                    //打开深度测试
    30         }
    31         break;
    32     case Qt::Key_L:                                     //L为开启关闭光源的切换键
    33         m_Light = !m_Light;
    34         if (m_Light)
    35         {
    36             glEnable(GL_LIGHTING);                      //开启光源
    37         }
    38         else
    39         {
    40             glDisable(GL_LIGHTING);                     //关闭光源
    41         }
    42         break;
    43     case Qt::Key_PageUp:                                //PageUp按下使木箱移向屏幕内部
    44         m_Deep -= 0.1f;
    45         break;
    46     case Qt::Key_PageDown:                              //PageDown按下使木箱移向观察者
    47         m_Deep += 0.1f;
    48         break;
    49     case Qt::Key_Up:                                    //Up按下减少m_xSpeed
    50         m_xSpeed -= 0.1f;
    51         break;
    52     case Qt::Key_Down:                                  //Down按下增加m_xSpeed
    53         m_xSpeed += 0.1f;
    54         break;
    55     case Qt::Key_Right:                                 //Right按下减少m_ySpeed
    56         m_ySpeed -= 0.1f;
    57         break;
    58     case Qt::Key_Left:                                  //Left按下增加m_ySpeed
    59         m_ySpeed += 0.1f;
    60         break;
    61     }
    62 }

    当B键的控制机制与L键相似,但注意到, 开启混合时还要关闭深度测试,关闭混合时还要打开深度测试,否则将发现立方体有一些面不见了!

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

  • 相关阅读:
    面试官:你说说互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景
    JAVA 线上故障排查套路,从 CPU、磁盘、内存、网络到GC 一条龙!
    面经分享:看非科班研究生如何转行斩获 ATM 大厂的 Offer ?
    Jmeter JDBC配置
    Jmeter JDBC连接
    js基础用法1
    java实现io读取数据
    mysql语句
    java修改linux文件
    linux永久或临时修改dns
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/14048051.html
Copyright © 2020-2023  润新知