Qt OpenGL 二次几何体
这次教程中,我将介绍二次几何体。利用二次几何体,我们可以很容易创建球、圆盘、圆柱和圆锥。
我们先介绍一下二次几何体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 二次几何体相关推荐
- C++ Opengl 绘制二次几何体源码
C++ Opengl 绘制二次几何体源码 项目开发环境 项目功能 项目演示 项目源码传送门 项目开发环境 开发语言:C++和IDE:VS2017,操作系统Windows版本windows SDK8.1 ...
- OpenGL(十二)——Qt OpenGL绕着坐标轴旋转多边形
OpenGL(十二)--Qt OpenGL绕着坐标轴旋转多边形 一.旋转多边形 前两篇介绍了如何绘制多边形,并且给多边形进行上色.本篇介绍如何旋转多边形. 多边形的旋转,在类中增加两个变量来控制这两个 ...
- Qt OpenGL(二十)——Qt OpenGL 核心模式版本
Qt OpenGL(二十)--Qt OpenGL 核心模式版本 一.写在前面 在之前的OpenGL教程(1~19)中,采用的方式都是固定渲染管线,也就是OpenGL3.2版本之前的写法,但是OpenG ...
- Qt OpenGL(二十八)——Qt OpenGL 核心模式-绘制一个正方体(正六面体)
Qt OpenGL(二十七)--Qt OpenGL 核心模式-绘制一个正方体(正六面体) 截止到上一篇文章,一川想使用Qt封装的类绘制一个旋转的彩色三角形的目标就实现了. 上一篇在介绍了使用变换矩阵的 ...
- Qt OpenGL(二十七)——Qt OpenGL 核心模式--EBO
Qt OpenGL(二十七)--Qt OpenGL 核心模式--EBO 一.四边形 上篇文章,一川绘制了能旋转的彩色三角形,在之前也介绍了VAO.VBO.但是EBO这个概念没有介绍,现在经历了,前几篇 ...
- OpenGL编程轻松入门之二次几何体
这一章我们讲一下二次几何物体的绘制.二次几何物体的绘制有几种不同的方式,在本例中可以看出不同的绘制方式的不同效果,如图十五所示. 例13:本例使用GLU库函数绘制了四个几何物体,分别为圆柱体.球体.圆 ...
- 【Qt OpenGL】Qt Creator中的3D绘图及动画教程
Qt Creator中的3D绘图及动画教程(参照NeHe) 刚刚学习了Qt Creator,发现Qt提供了QtOpenGL模块,对OpenGL做了不错的封装,这使得我们可以很轻松地在Qt程序中使用Op ...
- OpenGL(十六)——Qt OpenGL融合(将两张图片叠合成一张图片)
OpenGL(十六)--Qt OpenGL融合(将两张图片叠合成一张图片) 一.场景 在常用的项目场景中,我们经常会遇到将两个图片合在一起变成一张图片,这时候就会有前后之分,特别是两个物体合在一起的时 ...
- Qt OpenGL(08)通过递归细分正二十面体逼近球面
文章目录 Qt OpenGL 使用递归细分正二十面体逼近球体 下面就是绘制的代码: Widget.cpp 顶点着色器 片段着色器 Qt OpenGL 使用递归细分正二十面体逼近球体 在上一章中,我们讨 ...
最新文章
- 面试造飞机系列:用心整理的HashMap面试题,以后都不用担心了
- 可以查python题的_python练习题 -股票查询
- AtCoder Beginner Contest 072
- switch和if的比较
- 2021银川Problem D. Farm(不保证正确性)
- jboss war包放哪_如何将JBoss HR Employee Rewards项目放入云端
- linux 卸载nfs device is busy,umount.nfs: device is busy解决办法
- Nacos版本升级1.1.3 >> 1.3.1 —>再升级至1.3.2
- 6月首批国产游戏获批:共55款 腾讯B站上榜
- Java面向对象(继承、抽象类)
- batch size自适应log(1)
- 海思isp图像处理芯片_最新海思芯片3559A的功能简介
- 安卓开发——显示网速
- String的intern方法详解
- AS移动开发 类微信界面2_Activity的生命周期与跳转(持续更新中)
- 直播系统开发,直播平台源码切忌一成不变
- win7怎么进入安全模式_win7进入安全模式教程
- Epson针式打印机打印十六进制内容解决方案
- c++define的用法
- 设置zoom后,导致级联下拉不跟随输入框
热门文章
- php sg11加密方式,SG11加密使用、安装配置说明(11.4)
- 明日方舟苹果IOS脚本快速刷关卡刷图
- (附源码)SSM医院药品进销存系统JAVA计算机毕业设计项目
- 封装 电流密度 重布线_一种提高TSV热机械可靠性的复合结构及其制造方法与流程...
- 大厂h5开源视频系列-网易云音乐年度总结
- ci 连接myssql
- 使用Meshlab对CAD模型采样点云,并在PCL中显示
- 在mysql中unique唯一索引的作用_MySQL_MySQL中的唯一索引的简单学习教程,mysql 唯一索引UNIQUE一般用于不 - phpStudy...
- 可怕,朱茵变杨幂,流量一个亿丨AI变脸指南
- 【黎曼积分】第一型曲面积分公式推导