QT5 OpenGL (六, 键盘事件, 开关灯,放大缩小综合运用)
来源:互联网 发布:蔬菜水果配送软件 编辑:程序博客网 时间:2024/05/19 23:24
- 概要
- 实例效果图
- 立体图放大图
- 立体图缩小图
- 不加矢量开灯图
- 不加矢量关灯图
- 加矢量关灯图1
- 加矢量关灯图2
- 部分代码展示
- 主要内容解析
- QT键盘事件
- 立体图形的放大和缩小
- 上下左右键以及A键D争键控制x y z 轴旋转速度的快慢
- 开灯关灯以及矢量的实现原理
概要
多篇讲QT5 opengl的文章,从简单到复杂,几乎每篇都在原来的基友上有所增加新的内容, 感觉越到后面,越容易被opengl强大的功能所震撼, 而这篇文章主要是把前面所讲的一些内容进行综合, 然后再加入新的一些内容的运用。 首先, 加入键盘事件, 这个是学QT的人基本上都会的。 开关灯是这次一些新的内容, 放大缩小,是原来的内容,只是原来没有扩展开来。
实例效果图
为什么每次要先上效果图呢, 因为只有看到不错的效果图后,读者才有更大的兴趣读下去。
立体图放大图
立体图缩小图
不加矢量开灯图
不加矢量关灯图
加矢量关灯图1
加矢量关灯图2
部分代码展示
.h文件
#ifndef OPENGLWIDGET_H#define OPENGLWIDGET_H#include <QtOpenGL>class OpenglWidget : public QGLWidget{public: OpenglWidget(QWidget* parent = 0);protected: void initConnection(); void initializeGL(); void initWidget(); void paintGL(); void resizeGL(int width, int height); void loadGLTextures(); void keyPressEvent( QKeyEvent *e );private slots:private: GLfloat m_rotateTriangle; GLfloat m_rotateRectangle; GLfloat m_x; GLfloat m_y; GLfloat m_z; GLuint textur[3]; GLfloat m_zoom; GLfloat m_xSpeed; GLfloat m_ySpeed; GLfloat m_zSpeed; bool m_openLight; GLuint m_choiceTexture;};#endif // OPENGLWIDGET_H
.cpp文件
#include "openglwidget.h"GLfloat lightAmbient[4] = { 0.5, 0.5, 0.5, 1.0 };GLfloat lightDiffuse[4] = { 1.0, 1.0, 1.0, 1.0 };GLfloat lightPosition[4] = { 0.0, 0.0, 2.0, 1.0 };OpenglWidget::OpenglWidget(QWidget* parent) :QGLWidget(parent), m_rotateTriangle(0), m_rotateRectangle(0), m_x(0), m_y(0), m_z(0), m_zoom(-6), m_xSpeed(10), m_ySpeed(10), m_zSpeed(10), m_choiceTexture(0), m_openLight(false){ initWidget();}void OpenglWidget::initializeGL(){ loadGLTextures(); glEnable( GL_TEXTURE_2D ); glShadeModel( GL_SMOOTH ); glClearColor( 0.0, 0.0, 0.0, 0.5 ); glClearDepth( 1.0 ); glEnable( GL_DEPTH_TEST ); glDepthFunc( GL_LEQUAL ); glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); glLightfv( GL_LIGHT1, GL_AMBIENT, lightAmbient ); glLightfv( GL_LIGHT1, GL_DIFFUSE, lightDiffuse ); glLightfv( GL_LIGHT1, GL_POSITION, lightPosition ); glEnable( GL_LIGHT1 );}void OpenglWidget::initWidget(){ setGeometry( 400, 200, 640, 480 ); setWindowTitle(tr("opengl demo"));}void OpenglWidget::paintGL(){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef( -1.5, 0.0, m_zoom ); glRotatef( m_x, 1.0, 0.0, 0.0 ); glRotatef( m_y, 0.0, 1.0, 0.0 ); glRotatef( m_z, 0.0, 0.0, 1.0 ); glBindTexture( GL_TEXTURE_2D, textur[m_choiceTexture] ); glBegin( GL_QUADS ); glNormal3f( 0.0, 0.0, 1.0 ); glTexCoord2f( 0.0, 0.0 ); glVertex3f( -1.0, -1.0, 1.0 ); glTexCoord2f( 1.0, 0.0 ); glVertex3f( 1.0, -1.0, 1.0 ); glTexCoord2f( 1.0, 1.0 ); glVertex3f( 1.0, 1.0, 1.0 ); glTexCoord2f( 0.0, 1.0 ); glVertex3f( -1.0, 1.0, 1.0 ); glNormal3f( 0.0, 0.0, -1.0 ); glTexCoord2f( 1.0, 0.0 ); glVertex3f( -1.0, -1.0, -1.0 ); glTexCoord2f( 1.0, 1.0 ); glVertex3f( -1.0, 1.0, -1.0 ); glTexCoord2f( 0.0, 1.0 ); glVertex3f( 1.0, 1.0, -1.0 ); glTexCoord2f( 0.0, 0.0 ); glVertex3f( 1.0, -1.0, -1.0 ); glNormal3f( 0.0, 1.0, 0.0 ); glTexCoord2f( 0.0, 1.0 ); glVertex3f( -1.0, 1.0, -1.0 ); glTexCoord2f( 0.0, 0.0 ); glVertex3f( -1.0, 1.0, 1.0 ); glTexCoord2f( 1.0, 0.0 ); glVertex3f( 1.0, 1.0, 1.0 ); glTexCoord2f( 1.0, 1.0 ); glVertex3f( 1.0, 1.0, -1.0 ); glNormal3f( 0.0, -1.0, 0.0 ); glTexCoord2f( 1.0, 1.0 ); glVertex3f( -1.0, -1.0, -1.0 ); glTexCoord2f( 0.0, 1.0 ); glVertex3f( 1.0, -1.0, -1.0 ); glTexCoord2f( 0.0, 0.0 ); glVertex3f( 1.0, -1.0, 1.0 ); glTexCoord2f( 1.0, 0.0 ); glVertex3f( -1.0, -1.0, 1.0 ); glNormal3f( 1.0, 0.0, 0.0 ); glTexCoord2f( 1.0, 0.0 ); glVertex3f( 1.0, -1.0, -1.0 ); glTexCoord2f( 1.0, 1.0 ); glVertex3f( 1.0, 1.0, -1.0 ); glTexCoord2f( 0.0, 1.0 ); glVertex3f( 1.0, 1.0, 1.0 ); glTexCoord2f( 0.0, 0.0 ); glVertex3f( 1.0, -1.0, 1.0 ); glNormal3f( -1.0, 0.0, 0.0 ); glTexCoord2f( 0.0, 0.0 ); glVertex3f( -1.0, -1.0, -1.0 ); glTexCoord2f( 1.0, 0.0 ); glVertex3f( -1.0, -1.0, 1.0 ); glTexCoord2f( 1.0, 1.0 ); glVertex3f( -1.0, 1.0, 1.0 ); glTexCoord2f( 0.0, 1.0 ); glVertex3f( -1.0, 1.0, -1.0 ); glEnd(); glLoadIdentity(); glTranslatef( 1.5, 0.0, m_zoom ); glRotatef( m_x, 1.0, 0.0, 0.0 ); glRotatef( m_y, 0.0, 1.0, 0.0 ); glRotatef( m_z, 0.0, 0.0, 1.0 ); glBegin(GL_TRIANGLES); //三棱柱四面贴图 glTexCoord2f( 1, 1 ); glVertex3f( 0, 1, 0 ); glTexCoord2f( 0, 0 ); glVertex3f( 1, -1, 1 ); glTexCoord2f( 1, 0 ); glVertex3f( -1, -1, 1 ); glTexCoord2f( 1, 1 ); glVertex3f( 0, 1, 0 ); glTexCoord2f( 0, 0 ); glVertex3f( -1.0, -1.0, 1.0 ); glTexCoord2f( 1, 0 ); glVertex3f( -1.0, -1.0, -1.0 ); glTexCoord2f( 1, 1 ); glVertex3f( 0, 1, 0 ); glTexCoord2f( 0, 0 ); glVertex3f( -1.0, -1.0, -1.0 ); glTexCoord2f( 1, 0 ); glVertex3f( 1.0, -1.0, -1.0 ); glTexCoord2f( 1, 1 ); glVertex3f( 0, 1, 0 ); glTexCoord2f( 0, 0 ); glVertex3f( 1.0, -1.0, -1.0 ); glTexCoord2f( 1, 0 ); glVertex3f( 1.0, -1.0, 1.0 ); //三棱柱底面贴图 glTexCoord2f( 0, 0 ); glVertex3f( -1.0, -1.0, -1.0 ); glTexCoord2f( 1, 0 ); glVertex3f( 1.0, -1.0, -1.0 ); glTexCoord2f( 1, 1 ); glVertex3f( 1.0, -1.0, 1.0 ); glTexCoord2f( 1, 0 ); glVertex3f( 1.0, -1.0, -1.0 ); glTexCoord2f( 1, 1 ); glVertex3f( 1.0, -1.0, 1.0 ); glTexCoord2f( 0, 1 ); glVertex3f( -1.0, -1.0, 1.0 ); glTexCoord2f( 1, 1 ); glVertex3f( 1.0, -1.0, 1.0 ); glTexCoord2f( 0, 1 ); glVertex3f( -1.0, -1.0, 1.0 ); glTexCoord2f( 0, 0 ); glVertex3f( -1.0, -1.0, -1.0 ); glEnd(); m_x += m_xSpeed; m_y += m_ySpeed; m_z += m_zSpeed;}void OpenglWidget::resizeGL(int width, int height){ if(0 == height) { height = 1; } glViewport(0, 0, (GLint)width, (GLint)height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); // gluPerspective(45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0); GLdouble aspectRatio = (GLfloat)width/(GLfloat)height; GLdouble zNear = 0.1; GLdouble zFar = 100.0; GLdouble rFov = 45.0 * 3.14159265 / 180.0; glFrustum( -zNear * tan( rFov / 2.0 ) * aspectRatio, zNear * tan( rFov / 2.0 ) * aspectRatio, -zNear * tan( rFov / 2.0 ), zNear * tan( rFov / 2.0 ), zNear, zFar ); glMatrixMode(GL_MODELVIEW); glLoadIdentity();}void OpenglWidget::loadGLTextures(){ QImage tex; QImage buf; if ( !buf.load(":/images/dog.png")) { qWarning( "load image failed!" ); QImage dummy( 128, 128, QImage::Format_RGB32 ); dummy.fill( Qt::red); buf = dummy; } tex = QGLWidget::convertToGLFormat( buf ); glGenTextures( 3, &textur[0] ); //纹理一 glBindTexture( GL_TEXTURE_2D, textur[0] ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexImage2D( GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits() ); //纹理二 glBindTexture( GL_TEXTURE_2D, textur[1] ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexImage2D( GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits() ); //纹理三 glBindTexture( GL_TEXTURE_2D, textur[2] ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_NEAREST ); //gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGB, tex.width(), tex.height(), GL_RGBA, GL_UNSIGNED_BYTE, tex.bits() ); glTexImage2D( GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits() );}void OpenglWidget::keyPressEvent( QKeyEvent *e ){ switch ( e->key() ) { case Qt::Key_L: m_openLight = !m_openLight; if ( !m_openLight ) { glDisable( GL_LIGHTING ); } else { glEnable( GL_LIGHTING ); } updateGL(); break; case Qt::Key_F: m_choiceTexture += 1;; if ( m_choiceTexture > 2 ) { m_choiceTexture = 0; } updateGL(); break; case Qt::Key_W: m_zoom -= (GLfloat)0.2; updateGL(); break; case Qt::Key_S: m_zoom += (GLfloat)0.2; updateGL(); break; case Qt::Key_Up: m_xSpeed -= 1; updateGL(); break; case Qt::Key_Down: m_xSpeed += 1; updateGL(); break; case Qt::Key_Right: m_ySpeed += 1; updateGL(); break; case Qt::Key_Left: m_ySpeed -= 1; updateGL(); break; case Qt::Key_A: m_zSpeed += 1; updateGL(); break; case Qt::Key_D: m_zSpeed -= 1; updateGL(); break; case Qt::Key_Escape: close(); break; }}
主要内容解析
先易后难吧,从最简单的开始讲:
QT键盘事件
void keyPressEvent( QKeyEvent *e );
其实就是重写父类的键盘事件。 当用户按键时,系统就会自己过滤到这个按键的过程, 然后可以通过返回的事件拿到按下的对应的键,我们可以根据这个键来进行判断,然后再做相应的事件处理。
立体图形的放大和缩小
其实这里的放大缩小的原理是通过立体图形离显示屏幕的离距
glTranslatef( x, y, z );
也就是这个函数。。
它控制了三维空间里面的x, y, z 轴。
x 是相对于我们所创建的屏幕左右的移动, 而y是相对于我们所创建屏幕上下的移动, z就是我们面对屏幕深度的移动, 怎么来判断它的深度呢, 这里就用了一个放大,缩小 来达到这个效果的。
讲到这里,压制不住内心的想法,要进行一下扩展
glVertex3f(x,y,z) 与 glTranslatef( x, y, z );的区别, 前者是在一个立体图形固定在某个位置后,以它为坐标原点, 所构成的一个三维空间。
而后者是以我们所创建的整个屏幕为一个三个空间,屏幕的中文为三维空间的坐标原点。
这里又想到了glLoadIdentity(); 这个,如果还创建第二个立体图形时,不加这一个,第二个立体图形是随上一个在一个三维空间里面, 加了之后,就如同分开了两个三维空间,各自做各自的。
发现扯远了一点, 还是回到立体图形的放大和缩小问题上来,它就是直接通过控制,glTranslatef(x, y, z)的z 轴来进行放大缩小的
提得一提的是, 这里的z轴,跟我们高中学习的z轴好像有点不要样, 在高中,z轴向屏幕的深层方向应该是正方向, 反之为反方向, 而在opengl中,屏幕的深层方向为反方向, 反之为正方向, 对此我也表示,发明这些opengl的难道学数学时,在他们国家讲课的内容不一样??
上下左右键,以及A键D争键控制x, y, z 轴旋转速度的快慢。
glRotatef( m_x, 1.0, 0.0, 0.0 ); glRotatef( m_y, 0.0, 1.0, 0.0 ); glRotatef( m_z, 0.0, 0.0, 1.0 ); m_x += m_xSpeed; m_y += m_ySpeed; m_z += m_zSpeed; case Qt::Key_Right: m_ySpeed += 1; updateGL(); break; case Qt::Key_Left: m_ySpeed -= 1; updateGL(); break; case Qt::Key_A: m_zSpeed += 1; updateGL(); break; case Qt::Key_D: m_zSpeed -= 1; updateGL(); break; case Qt::Key_Up: m_xSpeed -= 1; updateGL(); break; case Qt::Key_Down: m_xSpeed += 1; updateGL(); break;
这上面是其中对应相关联地方的代码。其实理解并不难, 关键是掌握上几节所讲的内容。
主要是通过调用下面这个函数来进行控制:
WINGDIAPI void APIENTRY glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
angle 表示旋转的角度, x, y, z 分别表示围绕着那个方向来旋转。
当我们的angle 逐渐变大时,它的速度就变得越来越快。
我们项目里面用的m_x , m_y, m_z ,它们都只对应自己的轴,其它轴的值为零,这样的好处,是让我们更清楚地看到朝的某一个正方向的运动轨迹, 否则多个方向旋转就显得很乱。
然后到了讲有些生疏的开关灯了
开灯关灯以及矢量的实现原理
首先需要讲的是灯光效果三个很重要的元素:
环境光, 漫射光,以及 光源位置。
GLfloat lightAmbient[4] = { 0.5, 0.5, 0.5, 1.0 };
GLfloat lightDiffuse[4] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat lightPosition[4] = { 0.0, 0.0, 2.0, 1.0 };
它们都用一个浮点的数组保存四个值,而这些数组,最后给系统来识别, 环境光, 漫射光 是光就是强度, 前三个参数的值,值从0-1 表示由弱到强, 三个参数表示RGB三色分量,最后一个是alpha通道参数
而光源位置前三个参数,表示三维空间的x,y, z轴。最后一个表示指定的位置就是光源位置,这种解释感觉有点不靠谱,然而,我也不知道怎么说。
环境光,我们可以理解为我们的物体被四面八方的光源所包围,而漫射光理解为漫反射之内的吧, 就是不是镜子的平面反射。
glLightfv( GL_LIGHT1, GL_AMBIENT, lightAmbient ); glLightfv( GL_LIGHT1, GL_DIFFUSE, lightDiffuse ); glLightfv( GL_LIGHT1, GL_POSITION, lightPosition ); glEnable( GL_LIGHT1 ); case Qt::Key_L: m_openLight = !m_openLight; if ( !m_openLight ) { glDisable( GL_LIGHTING ); } else { glEnable( GL_LIGHTING ); } updateGL(); break;
这里通过绑定
我们设置的值,并开启灯光的使用权限 。
值得一提得是在贴图 的过程中, 我们有用到如下所示的接口。
glNormal3f( 0.0, 0.0, 1.0 );
这就是光源的矢量, 表示光的照射方面。
就是在x, y, z三个值中, 当两个为0时, 就是朝另外一个不为0的方面, 正负,表示方向相反。
如果不加这个关灯后,就全暗了,加了之后就是确定光照在这个矢量方向上暗。
不知不觉写了之么多, 可能里面有一些理解有误的地方,希望大家多多指正。
- QT5 OpenGL (六, 键盘事件, 开关灯,放大缩小综合运用)
- MKMapView放大缩小事件
- 浏览器放大缩小事件
- OC_图片放大缩小_移动手势综合
- OpenGL键盘事件处理
- 放大 缩小
- 【放大、缩小】
- Android opengl 正方形 手势三维旋转、缩小、放大
- Opencv学习笔记(六)--图像的放大和缩小
- 图片放大缩小的区域点击事件代码例子
- 图片放大缩小的区域点击事件代码例子
- 图片放大缩小的区域点击事件代码例子
- 图片放大缩小的区域点击事件代码例子
- flex4.6实现图片放大缩小及鼠标拖放事件
- 实现图片放大缩小,点击热点响应事件
- 实现图片放大缩小,点击热点响应事件
- 【触摸事件】单击移动图片+双指放大缩小图片
- hightCharts放大缩小图表时,重新获取数据事件
- frame,iframe,frameset用法和区别
- 数据操作
- 使用telnet玩一下http
- An App ID with Identifier 'com.domainName.AppName' is not available. Please enter a different string
- (OpenCV)HOG源码分析
- QT5 OpenGL (六, 键盘事件, 开关灯,放大缩小综合运用)
- 初识NoSQL
- C++第二次实验-类和对象
- NTP协议
- Unity 音频播放里的坑
- PHP获取日期为星期几的代码
- android 常见错误集合查询
- 虚拟机Ubuntu Server(宿主Win7)gcc
- 在xml文件中定义图片数组