这次教程中,我将介绍二次几何体。利用二次几何体,我们可以很容易创建球、圆盘、圆柱和圆锥。

我们先介绍一下二次几何体GLUquadric(NeHe教程用的是GLUquadricObj,源代码中GLUquadricObj是GLUquadric的别名),其实它本质上是一个二次方程,即a1x^2 + a2y^2 + a3z^2 + a4xy + a5yz + a6zx + a7x + a8y + a9z + a10 = 0。要知道,任何一个空间规则曲面(包括平面)都是可以用二次方程表示出来的,因此OpenGL利用二次几何体来实现一些函数,帮助用户更简单的绘画出常用的空间曲面。

程序运行时效果如下:

下面进入教程:

我们将在第07课的基础上修改代码,我只会对新增代码作解释,首先打开myglwidget.h文件,将类声明更改如下:

 1 #ifndef MYGLWIDGET_H2 #define MYGLWIDGET_H3  4 #include <QWidget>5 #include <QGLWidget>6  7 class GLUquadric;8 class MyGLWidget : public QGLWidget9 {
10     Q_OBJECT
11 public:
12     explicit MyGLWidget(QWidget *parent = 0);
13     ~MyGLWidget();
14
15 protected:
16     //对3个纯虚函数的重定义
17     void initializeGL();
18     void resizeGL(int w, int h);
19     void paintGL();
20
21     void keyPressEvent(QKeyEvent *event);           //处理键盘按下事件
22
23 private:
24     void glDrawCube();                              //绘制立方体
25
26 private:
27     bool fullscreen;                                //是否全屏显示
28
29     QString m_FileName;                             //图片的路径及文件名
30     GLuint m_Texture;                               //储存一个纹理
31
32     bool m_Light;                                   //光源的开/关
33     GLfloat m_xRot;                                 //x旋转角度
34     GLfloat m_yRot;                                 //y旋转角度
35     GLfloat m_xSpeed;                               //x旋转速度
36     GLfloat m_ySpeed;                               //y旋转速度
37     GLfloat m_Deep;                                 //深入屏幕的距离
38
39     int m_Part1;                                    //圆盘的起始角度
40     int m_Part2;                                    //圆盘的结束角度
41     int m_P1;                                       //增量1
42     int m_P2;                                       //增量2
43     GLUquadric *m_Quadratic;                        //二次几何体
44     GLuint m_Object;                                //绘制对象标示符
45 };
46
47 #endif // MYGLWIDGET_H

首先我们在类前面增加了GLUquadric的类声明。接着我们增加了6个变量,前4个变量用于控制绘制“部分圆盘”的,下面会解释。然后我们定义一个二次几何体对象指针和一个GLuint变量,二次几何体就不解释了,m_Object是配合键盘控制来完成图形之间切换的。最后我们增加了一个函数声明glDrawCube(),这个函数是用来绘制立方体的。

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

接下来,我们需要打开myglwidget.cpp,在构造函数中初始化新增变量(除了m_Quadratic)并修改析构函数(删除掉创建的二次几何体),很简单不多解释,具体代码如下:

 1 MyGLWidget::MyGLWidget(QWidget *parent) :2     QGLWidget(parent)3 {4     fullscreen = false;5     m_FileName = "D:/QtOpenGL/QtImage/Wall1.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     m_Part1 = 0;
15     m_Part2 = 0;
16     m_P1 = 0;
17     m_P2 = 1;
18     m_Object = 0;
19
20     QTimer *timer = new QTimer(this);                   //创建一个定时器
21     //将定时器的计时信号与updateGL()绑定
22     connect(timer, SIGNAL(timeout()), this, SLOT(updateGL()));
23     timer->start(10);                                   //以10ms为一个计时周期
24 }
1 MyGLWidget::~MyGLWidget()
2 {
3     gluDeleteQuadric(m_Quadratic);
4 }

继续,我们需要定义我们新增的glDrawCube()函数了,其实就是画一个纹理立方体,完全可以从第07课的paintGL()函数中复制过来,不再多作解释,代码如下:

 1 void MyGLWidget::glDrawCube()2 {3     glBegin(GL_QUADS);                                  //开始绘制立方体4         glNormal3f(0.0f, 1.0f, 0.0f);5         glTexCoord2f(1.0f, 1.0f);6         glVertex3f(1.0f, 1.0f, -1.0f);                  //右上(顶面)7         glTexCoord2f(0.0f, 1.0f);8         glVertex3f(-1.0f, 1.0f, -1.0f);                 //左上(顶面)9         glTexCoord2f(0.0f, 0.0f);
10         glVertex3f(-1.0f, 1.0f, 1.0f);                  //左下(顶面)
11         glTexCoord2f(1.0f, 0.0f);
12         glVertex3f(1.0f, 1.0f, 1.0f);                   //右下(顶面)
13
14         glNormal3f(0.0f, -1.0f, 0.0f);
15         glTexCoord2f(0.0f, 0.0f);
16         glVertex3f(1.0f, -1.0f, 1.0f);                  //右上(底面)
17         glTexCoord2f(1.0f, 0.0f);
18         glVertex3f(-1.0f, -1.0f, 1.0f);                 //左上(底面)
19         glTexCoord2f(1.0f, 1.0f);
20         glVertex3f(-1.0f, -1.0f, -1.0f);                //左下(底面)
21         glTexCoord2f(0.0f, 1.0f);
22         glVertex3f(1.0f, -1.0f, -1.0f);                 //右下(底面)
23
24         glNormal3f(0.0f, 0.0f, 1.0f);
25         glTexCoord2f(1.0f, 1.0f);
26         glVertex3f(1.0f, 1.0f, 1.0f);                   //右上(前面)
27         glTexCoord2f(0.0f, 1.0f);
28         glVertex3f(-1.0f, 1.0f, 1.0f);                  //左上(前面)
29         glTexCoord2f(0.0f, 0.0f);
30         glVertex3f(-1.0f, -1.0f, 1.0f);                 //左下(前面)
31         glTexCoord2f(1.0f, 0.0f);
32         glVertex3f(1.0f, -1.0f, 1.0f);                  //右下(前面)
33
34         glNormal3f(0.0f, 0.0f, -1.0f);
35         glTexCoord2f(0.0f, 0.0f);
36         glVertex3f(1.0f, -1.0f, -1.0f);                 //右上(后面)
37         glTexCoord2f(1.0f, 0.0f);
38         glVertex3f(-1.0f, -1.0f, -1.0f);                //左上(后面)
39         glTexCoord2f(1.0f, 1.0f);
40         glVertex3f(-1.0f, 1.0f, -1.0f);                 //左下(后面)
41         glTexCoord2f(0.0f, 1.0f);
42         glVertex3f(1.0f, 1.0f, -1.0f);                  //右下(后面)
43
44         glNormal3f(-1.0f, 0.0f, 0.0f);
45         glTexCoord2f(1.0f, 1.0f);
46         glVertex3f(-1.0f, 1.0f, 1.0f);                  //右上(左面)
47         glTexCoord2f(0.0f, 1.0f);
48         glVertex3f(-1.0f, 1.0f, -1.0f);                 //左上(左面)
49         glTexCoord2f(0.0f, 0.0f);
50         glVertex3f(-1.0f, -1.0f, -1.0f);                //左下(左面)
51         glTexCoord2f(1.0f, 0.0f);
52         glVertex3f(-1.0f, -1.0f, 1.0f);                 //右下(左面)
53
54         glNormal3f(1.0f, 0.0f, 0.0f);
55         glTexCoord2f(1.0f, 1.0f);
56         glVertex3f(1.0f, 1.0f, -1.0f);                  //右上(右面)
57         glTexCoord2f(0.0f, 1.0f);
58         glVertex3f(1.0f, 1.0f, 1.0f);                   //左上(右面)
59         glTexCoord2f(0.0f, 0.0f);
60         glVertex3f(1.0f, -1.0f, 1.0f);                  //左下(右面)
61         glTexCoord2f(1.0f, 0.0f);
62         glVertex3f(1.0f, -1.0f, -1.0f);                 //右下(右面)
63     glEnd();                                            //立方体绘制结束
64 }

然后我们需要修改一下initializeGL()函数,在其中完成对m_Quadratic的初始化,具体代码如下:

 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     m_Quadratic = gluNewQuadric();                        //创建二次几何体
15     gluQuadricNormals(m_Quadratic, GLU_SMOOTH);           //使用平滑法线
16     gluQuadricTexture(m_Quadratic, GL_TRUE);              //使用纹理
17
18     //光源部分
19     GLfloat LightAmbient[] = {0.5f, 0.5f, 0.5f, 1.0f};  //环境光参数
20     GLfloat LightDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};  //漫散光参数
21     GLfloat LightPosition[] = {0.0f, 0.0f, 2.0f, 1.0f}; //光源位置
22     glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);     //设置环境光
23     glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);     //设置漫射光
24     glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);   //设置光源位置
25     glEnable(GL_LIGHT1);                                //启动一号光源
26 }

注意到我们增加了三行代码,首先调用gluNewQuadric()创建了一个二次几何体对象,并让m_Quadratic指向这个二次几何体。然后第二行代码将在二次曲面的表面创建平滑的法向量,这样当灯光照上去的时候将会好看些。最后我们使在二次曲面表面的纹理映射有效。

还有就是paintGL()函数了,最近几课,我们通过分过程渐渐让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);                    //移入屏幕5.0单位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     switch(m_Object)
11     {
12     case 0:                                             //绘制立方体
13         glDrawCube();
14         break;
15     case 1:                                             //绘制圆柱体
16         glTranslatef(0.0f, 0.0f, -1.5f);
17         gluCylinder(m_Quadratic, 1.0f, 1.0f, 3.0f, 64, 64);
18         break;
19     case 2:                                             //绘制圆盘
20         gluDisk(m_Quadratic, 0.5f, 1.5f, 64, 64);
21         break;
22     case 3:                                             //绘制球
23         gluSphere(m_Quadratic, 1.3f, 64, 64);
24         break;
25     case 4:                                             //绘制圆锥
26         glTranslatef(0.0f, 0.0f, -1.5f);
27         gluCylinder(m_Quadratic, 1.0f, 0.0f, 3.0f, 64, 64);
28         break;
29     case 5:                                             //绘制部分圆盘
30         m_Part1 += m_P1;
31         m_Part2 += m_P2;
32
33         if (m_Part1 > 359)
34         {
35             m_P1 = 0;
36             m_Part1 = 0;
37             m_P2 = 1;
38             m_Part2 = 0;
39         }
40         if (m_Part2 > 359)
41         {
42             m_P1 = 1;
43             m_P2 = 0;
44         }
45
46         gluPartialDisk(m_Quadratic, 0.5f, 1.5f, 64, 64, m_Part1, m_Part2-m_Part1);
47         break;
48     }
49
50     m_xRot += m_xSpeed;                                 //x轴旋转
51     m_yRot += m_ySpeed;                                 //y轴旋转
52 }

我们将原来的绘制立方体部分的代码换成了一个switch()语句,我们利用m_Object来确定画哪一种物体(具体哪个值对应哪个,请大家参照注释)。我们后面讨论绘制这些物体调用的函数时,会忽略第一个参数m_Quadratic,这个参数将被除立方体外的所有对象使用。由于前面已经解释过二次几何体的实质,我们在讨论下面函数的参数时将忽略它。

我们创建的第2个对象是一个圆柱体:参数2是圆柱的底面半径;参数3是圆柱的顶面半径;参数4是圆柱的高度(表面我们也可以绘制圆台的);参数5是纬线(环绕z轴有多少细分);参数6是经线(沿着z轴有多少细分)。细分越多该对象就越细致,其实我们可以用gluCylinder来绘制多棱柱的,只要把参数5和参数6换成对应的棱数就行了。

第3个对象是一个CD一样的盘子:参数2是盘子的内圆半径,该参数可以为0.0,则表示在盘子中间没孔,内圆半径越大孔越大;参数3表示外圆半径,这个参数必须比内圆半径大;参数4是组成该盘子切片的数量;参数5是组成盘子的环的数量,环很像唱片上的轨迹。同样,把参数4改成边数,同样可以得到带孔(不带孔)的多边形。

第4个对象是球:参数2是球的半径;和圆柱一样,参数3是纬线;参数4是经线。细分越多球看起来就越平滑。

第5个对象是圆锥:其实和绘制圆柱是一样的,只是把顶面半径设置为0.0,这样顶面就成了一个点。同样参考上面说的方法可以绘制多棱锥。

第6个对象将被gluPartialDisk()函数创建。相比于gluDisk()函数,gluPartialDisk()多了两个新参数。参数6是我们想要绘制的分部盘子的开始角度,参数6是旋转角,也就是转过的调度。我们将要增加旋转角,这将引起盘子沿顺时针方向缓慢的被绘制在屏幕上。一旦旋转角达到360度,我们将开始增加开始角度,这样盘子看起来就像是被逐渐地抹去一样,我们将重复这两个过程。

最后我们修改一下键盘控制函数,不多解释了,具体代码如下:

 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_Space:                                 //空格为物体的切换键
31         m_Object++;
32         if (m_Object == 6)
33         {
34             m_Object = 0;
35         }
36         break;
37     case Qt::Key_PageUp:                                //PageUp按下使木箱移向屏幕内部
38         m_Deep -= 0.1f;
39         break;
40     case Qt::Key_PageDown:                              //PageDown按下使木箱移向观察者
41         m_Deep += 0.1f;
42         break;
43     case Qt::Key_Up:                                    //Up按下减少m_xSpeed
44         m_xSpeed -= 0.1f;
45         break;
46     case Qt::Key_Down:                                  //Down按下增加m_xSpeed
47         m_xSpeed += 0.1f;
48         break;
49     case Qt::Key_Right:                                 //Right按下减少m_ySpeed
50         m_ySpeed -= 0.1f;
51         break;
52     case Qt::Key_Left:                                  //Left按下增加m_ySpeed
53         m_ySpeed += 0.1f;
54         break;
55     }
56 }

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

Qt OpenGL 二次几何体相关推荐

  1. C++ Opengl 绘制二次几何体源码

    C++ Opengl 绘制二次几何体源码 项目开发环境 项目功能 项目演示 项目源码传送门 项目开发环境 开发语言:C++和IDE:VS2017,操作系统Windows版本windows SDK8.1 ...

  2. OpenGL(十二)——Qt OpenGL绕着坐标轴旋转多边形

    OpenGL(十二)--Qt OpenGL绕着坐标轴旋转多边形 一.旋转多边形 前两篇介绍了如何绘制多边形,并且给多边形进行上色.本篇介绍如何旋转多边形. 多边形的旋转,在类中增加两个变量来控制这两个 ...

  3. Qt OpenGL(二十)——Qt OpenGL 核心模式版本

    Qt OpenGL(二十)--Qt OpenGL 核心模式版本 一.写在前面 在之前的OpenGL教程(1~19)中,采用的方式都是固定渲染管线,也就是OpenGL3.2版本之前的写法,但是OpenG ...

  4. Qt OpenGL(二十八)——Qt OpenGL 核心模式-绘制一个正方体(正六面体)

    Qt OpenGL(二十七)--Qt OpenGL 核心模式-绘制一个正方体(正六面体) 截止到上一篇文章,一川想使用Qt封装的类绘制一个旋转的彩色三角形的目标就实现了. 上一篇在介绍了使用变换矩阵的 ...

  5. Qt OpenGL(二十七)——Qt OpenGL 核心模式--EBO

    Qt OpenGL(二十七)--Qt OpenGL 核心模式--EBO 一.四边形 上篇文章,一川绘制了能旋转的彩色三角形,在之前也介绍了VAO.VBO.但是EBO这个概念没有介绍,现在经历了,前几篇 ...

  6. OpenGL编程轻松入门之二次几何体

    这一章我们讲一下二次几何物体的绘制.二次几何物体的绘制有几种不同的方式,在本例中可以看出不同的绘制方式的不同效果,如图十五所示. 例13:本例使用GLU库函数绘制了四个几何物体,分别为圆柱体.球体.圆 ...

  7. 【Qt OpenGL】Qt Creator中的3D绘图及动画教程

    Qt Creator中的3D绘图及动画教程(参照NeHe) 刚刚学习了Qt Creator,发现Qt提供了QtOpenGL模块,对OpenGL做了不错的封装,这使得我们可以很轻松地在Qt程序中使用Op ...

  8. OpenGL(十六)——Qt OpenGL融合(将两张图片叠合成一张图片)

    OpenGL(十六)--Qt OpenGL融合(将两张图片叠合成一张图片) 一.场景 在常用的项目场景中,我们经常会遇到将两个图片合在一起变成一张图片,这时候就会有前后之分,特别是两个物体合在一起的时 ...

  9. Qt OpenGL(08)通过递归细分正二十面体逼近球面

    文章目录 Qt OpenGL 使用递归细分正二十面体逼近球体 下面就是绘制的代码: Widget.cpp 顶点着色器 片段着色器 Qt OpenGL 使用递归细分正二十面体逼近球体 在上一章中,我们讨 ...

最新文章

  1. 面试造飞机系列:用心整理的HashMap面试题,以后都不用担心了
  2. 可以查python题的_python练习题 -股票查询
  3. AtCoder Beginner Contest 072
  4. switch和if的比较
  5. 2021银川Problem D. Farm(不保证正确性)
  6. jboss war包放哪_如何将JBoss HR Employee Rewards项目放入云端
  7. linux 卸载nfs device is busy,umount.nfs: device is busy解决办法
  8. Nacos版本升级1.1.3 >> 1.3.1 —>再升级至1.3.2
  9. 6月首批国产游戏获批:共55款 腾讯B站上榜
  10. Java面向对象(继承、抽象类)
  11. batch size自适应log(1)
  12. 海思isp图像处理芯片_最新海思芯片3559A的功能简介
  13. 安卓开发——显示网速
  14. String的intern方法详解
  15. AS移动开发 类微信界面2_Activity的生命周期与跳转(持续更新中)
  16. 直播系统开发,直播平台源码切忌一成不变
  17. win7怎么进入安全模式_win7进入安全模式教程
  18. Epson针式打印机打印十六进制内容解决方案
  19. c++define的用法
  20. 设置zoom后,导致级联下拉不跟随输入框

热门文章

  1. php sg11加密方式,SG11加密使用、安装配置说明(11.4)
  2. 明日方舟苹果IOS脚本快速刷关卡刷图
  3. (附源码)SSM医院药品进销存系统JAVA计算机毕业设计项目
  4. 封装 电流密度 重布线_一种提高TSV热机械可靠性的复合结构及其制造方法与流程...
  5. 大厂h5开源视频系列-网易云音乐年度总结
  6. ci 连接myssql
  7. 使用Meshlab对CAD模型采样点云,并在PCL中显示
  8. 在mysql中unique唯一索引的作用_MySQL_MySQL中的唯一索引的简单学习教程,mysql 唯一索引UNIQUE一般用于不 - phpStudy...
  9. 可怕,朱茵变杨幂,流量一个亿丨AI变脸指南
  10. 【黎曼积分】第一型曲面积分公式推导