zl程序教程

您现在的位置是:首页 >  工具

当前栏目

Qt OpenGL 光照和键盘控制

Qt控制 键盘 OpenGL 光照
2023-09-14 09:05:12 时间

这次教程中,我们将添加光照和键盘控制,它让程序看起来更美观。我将教大家如何使用键盘来移动场景中的对象,还会教大家在OpenGL场景中应用简单的光照,让我们的程序更加视觉效果更好且受我们控制。

程序运行时效果如下:

 

下面进入教程:

我们这次将在第06课的基础上修改代码,首先打开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     bool m_Light;                                   //光源的开/关
28     
29     GLfloat m_xRot;                                 //x旋转角度
30     GLfloat m_yRot;                                 //y旋转角度
31     GLfloat m_xSpeed;                               //x旋转速度
32     GLfloat m_ySpeed;                               //y旋转速度
33     GLfloat m_Deep;                                 //深入屏幕的距离
34 };
35  
36 #endif // MYGLWIDGET_H

CSDN QT技术栈大纲:Qt开发必备技术栈学习路线和资料

增加了一个布尔变量表示光源的开关,剩下的五个浮点变量用于控制对象的旋转角度,旋转速度以及距离屏幕的位置。

接下来,我们需要打开myglwidget.cpp,加上声明#include <QTimer>,在构造函数中对新增变量(除了m_Texture)进行初始化,同样不作过多解释,代码如下:

 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     
 8     m_xRot = 0.0f;
 9     m_yRot = 0.0f;
10     m_xSpeed = 0.0f;
11     m_ySpeed = 0.0f;
12     m_Deep = -5.0f;
13     
14     QTimer *timer = new QTimer(this);                   //创建一个定时器
15     //将定时器的计时信号与updateGL()绑定
16     connect(timer, SIGNAL(timeout()), this, SLOT(updateGL()));
17     timer->start(10);                                   //以10ms为一个计时周期
18 }

然后,我们要来添加光照,只需要在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     GLfloat LightAmbient[] = {0.5f, 0.5f, 0.5f, 1.0f};  //环境光参数
15     GLfloat LightDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};  //漫散光参数
16     GLfloat LightPosition[] = {0.0f, 0.0f, 2.0f, 1.0f}; //光源位置
17     glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);     //设置环境光
18     glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);     //设置漫射光
19     glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);   //设置光源位置
20     glEnable(GL_LIGHT1);                                //启动一号光源
21 }

首先我们分别定义环境光参数,漫射光参数以及光源位置。环境光来自于四面八方,所以场景中的对象都处于环境光的照射中;漫射光由特定的光源产生,并在场景中的对象表明产生反射。处于漫射光直接照射下的任何对象表面都变得很亮,而几乎未被照到的区域显得要暗一些。这样我们所创建的木板箱的棱边上就会产生很不错的阴影效果。

创建光源的过程和颜色的创建完全一致,前三个参数分别是RGB三色分量,最后一个是alpha通道参数。最后光源位置前三个参数和glTranslate中的一样,一次表示x、y、z轴上的位移,最后一个参数取为1.0f,这将告诉OpenGL这里指定的坐标就是光源的位置,以后的教程中我会多加解释。

接着开始设置光源,使得光源GL_LIGHT1开始发光,然后是设置光源位置(位于木箱原中心在z方向移向观察者2.0单位),最后我们启用一号光源。要注意的是,我们还没有启用GL_LIGHTING,所以是看不见任何光线的。记住,只对光源进行设置、定位、甚至启用,光源都不会工作,除非我们启用GL_LIGHTING。

还有是对paintGL()函数的修改,修改后具体代码如下:

 1 void MyGLWidget::paintGL()                              //从这里开始进行所以的绘制
 2 {
 3     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除屏幕和深度缓存
 4     glLoadIdentity();                                   //重置模型观察矩阵
 5     glTranslatef(0.0f, 0.0f, m_Deep);                   //移入屏幕
 6     glRotatef(m_xRot, 1.0f, 0.0f, 0.0f);                //绕x轴旋转
 7     glRotatef(m_yRot, 0.0f, 1.0f, 0.0f);                //绕y轴旋转
 8  
 9     glBindTexture(GL_TEXTURE_2D, m_Texture);            //选择纹理
10     glBegin(GL_QUADS);                                  //开始绘制立方体
11         glNormal3f(0.0f, 1.0f, 0.0f);
12         glTexCoord2f(1.0f, 1.0f);
13         glVertex3f(1.0f, 1.0f, -1.0f);                  //右上(顶面)
14         glTexCoord2f(0.0f, 1.0f);
15         glVertex3f(-1.0f, 1.0f, -1.0f);                 //左上(顶面)
16         glTexCoord2f(0.0f, 0.0f);
17         glVertex3f(-1.0f, 1.0f, 1.0f);                  //左下(顶面)
18         glTexCoord2f(1.0f, 0.0f);
19         glVertex3f(1.0f, 1.0f, 1.0f);                   //右下(顶面)
20  
21         glNormal3f(0.0f, -1.0f, 0.0f);
22         glTexCoord2f(0.0f, 0.0f);
23         glVertex3f(1.0f, -1.0f, 1.0f);                  //右上(底面)
24         glTexCoord2f(1.0f, 0.0f);
25         glVertex3f(-1.0f, -1.0f, 1.0f);                 //左上(底面)
26         glTexCoord2f(1.0f, 1.0f);
27         glVertex3f(-1.0f, -1.0f, -1.0f);                //左下(底面)
28         glTexCoord2f(0.0f, 1.0f);
29         glVertex3f(1.0f, -1.0f, -1.0f);                 //右下(底面)
30  
31         glNormal3f(0.0f, 0.0f, 1.0f);
32         glTexCoord2f(1.0f, 1.0f);
33         glVertex3f(1.0f, 1.0f, 1.0f);                   //右上(前面)
34         glTexCoord2f(0.0f, 1.0f);
35         glVertex3f(-1.0f, 1.0f, 1.0f);                  //左上(前面)
36         glTexCoord2f(0.0f, 0.0f);
37         glVertex3f(-1.0f, -1.0f, 1.0f);                 //左下(前面)
38         glTexCoord2f(1.0f, 0.0f);
39         glVertex3f(1.0f, -1.0f, 1.0f);                  //右下(前面)
40  
41         glNormal3f(0.0f, 0.0f, -1.0f);
42         glTexCoord2f(0.0f, 0.0f);
43         glVertex3f(1.0f, -1.0f, -1.0f);                 //右上(后面)
44         glTexCoord2f(1.0f, 0.0f);
45         glVertex3f(-1.0f, -1.0f, -1.0f);                //左上(后面)
46         glTexCoord2f(1.0f, 1.0f);
47         glVertex3f(-1.0f, 1.0f, -1.0f);                 //左下(后面)
48         glTexCoord2f(0.0f, 1.0f);
49         glVertex3f(1.0f, 1.0f, -1.0f);                  //右下(后面)
50  
51         glNormal3f(-1.0f, 0.0f, 0.0f);
52         glTexCoord2f(1.0f, 1.0f);
53         glVertex3f(-1.0f, 1.0f, 1.0f);                  //右上(左面)
54         glTexCoord2f(0.0f, 1.0f);
55         glVertex3f(-1.0f, 1.0f, -1.0f);                 //左上(左面)
56         glTexCoord2f(0.0f, 0.0f);
57         glVertex3f(-1.0f, -1.0f, -1.0f);                //左下(左面)
58         glTexCoord2f(1.0f, 0.0f);
59         glVertex3f(-1.0f, -1.0f, 1.0f);                 //右下(左面)
60  
61         glNormal3f(1.0f, 0.0f, 0.0f);
62         glTexCoord2f(1.0f, 1.0f);
63         glVertex3f(1.0f, 1.0f, -1.0f);                  //右上(右面)
64         glTexCoord2f(0.0f, 1.0f);
65         glVertex3f(1.0f, 1.0f, 1.0f);                   //左上(右面)
66         glTexCoord2f(0.0f, 0.0f);
67         glVertex3f(1.0f, -1.0f, 1.0f);                  //左下(右面)
68         glTexCoord2f(1.0f, 0.0f);
69         glVertex3f(1.0f, -1.0f, -1.0f);                 //右下(右面)
70     glEnd();                                            //立方体绘制结束
71  
72     m_xRot += m_xSpeed;                                 //x轴旋转
73     m_yRot += m_ySpeed;                                 //y轴旋转
74 }

除了旋转及移动上作了修改外(相信大家能看懂),多了glNormal3f()函数的调用。该函数指定一条法线,法线告诉OpenGL这个多边形的朝向,并指明多边形的正面和背面,如果没有法线,什么怪事情都可能发生:不该亮的面被照亮了,多边形的背面也被照亮了…还要注意的是,法线应指向多边形的外侧。
最后两行代码作了一定的修改,利用变量m_xSpeed、m_ySpeed来控制立方体的旋转速度。

最后当然就是键盘控制了,具体代码如下(相信大家结合注释可以很容易看懂):

 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_L:                                     //L为开启关闭光源的切换键
20         m_Light = !m_Light;
21         if (m_Light)
22         {
23             glEnable(GL_LIGHTING);                      //开启光源
24         }
25         else
26         {
27             glDisable(GL_LIGHTING);                     //关闭光源
28         }
29         break;
30     case Qt::Key_PageUp:                                //PageUp按下使木箱移向屏幕内部
31         m_Deep -= 0.1f;
32         break;
33     case Qt::Key_PageDown:                              //PageDown按下使木箱移向观察者
34         m_Deep += 0.1f;
35         break;
36     case Qt::Key_Up:                                    //Up按下减少m_xSpeed
37         m_xSpeed -= 0.1f;
38         break;
39     case Qt::Key_Down:                                  //Down按下增加m_xSpeed
40         m_xSpeed += 0.1f;
41         break;
42     case Qt::Key_Right:                                 //Right按下减少m_ySpeed
43         m_ySpeed -= 0.1f;
44         break;
45     case Qt::Key_Left:                                  //Left按下增加m_ySpeed
46         m_ySpeed += 0.1f;
47         break;
48     }
49 }

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓