QT5 OpenGL (六, 键盘事件, 开关灯,放大缩小综合运用)
概要
多篇讲QT5 opengl的文章,从简单到复杂,差点儿每篇都在原来的基友上有所增加新的内容, 感觉越到后面,越easy被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 (六, 键盘事件, 开关灯,放大缩小综合运用)的更多相关文章
- GreenOpenPaint的实现(四)放大缩小处理滚动事件
放大缩小看似简单,实际上还是比较复杂的.所以专门拿出来说明. 缩放这块,主要就是处理m_pDoc->m_scalefactor void CGreenOpenPaintView::OnButto ...
- 自定义mousewheel事件,实现图片放大缩小功能实现
本文是承接 上一篇的<自定义鼠标滚动事件> 的基础上实现的,建议大家先看一下上一篇的mousewheel的实现,再浏览下文: 上篇中我们介绍到: $element.mousewheel( ...
- Javascript 事件对象(六)键盘事件
keyCode获取用户按下键盘的哪个按键 <!DOCTYPE HTML> <html> <head> <meta http-equiv="Conte ...
- openGL 初试 绘制三角形 和添加鼠标键盘事件
code: #include <gl/glut.h> #include <stdlib.h> void render(void); void keyboard(unsigned ...
- Unity3D笔记十六 输入输出-键盘事件、鼠标事件
输入与控制操作Unity为开发者提供了Input类库,其中包括键盘事件.鼠标事件和触摸事件等一切跨平台所需要的控制事件. 一.键盘事件 1.按下事件 Input.GetKeyDown():如果按键被按 ...
- 基于OpenGL编写一个简易的2D渲染框架-07 鼠标事件和键盘事件
这次为程序添加鼠标事件和键盘事件 当检测到鼠标事件和键盘事件的信息时,捕获其信息并将信息传送到需要信息的对象处理.为此,需要一个可以分派信息的对象,这个对象能够正确的把信息交到正确的对象. 实现思路: ...
- 六、React 键盘事件 表单事件 事件对象以及React中的ref获取dom节点 、React实现类似Vue的双向数据绑定
接:https://www.cnblogs.com/chenxi188/p/11782349.html 事件对象 .键盘事件. 表单事件 .ref获取dom节点.React实现类似vue双向数据绑定 ...
- js 鼠标和键盘事件
js 鼠标和键盘事件 鼠标事件 聚焦事件 离焦事件 鼠标单击和双击 鼠标的其他事件 鼠标事件对象 键盘事件 鼠标事件 聚焦事件 <input type="text" id=& ...
- PhotoView实现图片随手势的放大缩小的效果
项目需求:在listView的条目中如果有图片,点击条目,实现图片的放大,并且图片可以根据手势来控制图片放大缩小的比例.类似于微信朋友圈中查看好友发布的照片所实现的效果. 思路是这样的:当点击条目的时 ...
随机推荐
- warning:deprecated conversion from string constant to 'char *'
warning:deprecated conversion from string constant to 'char *' 解决方式 #include <iostream> using ...
- Unity3D:实现人物转向与移动
在网上有非常多通过射线方式实现的人物行走控制脚本,可是假设仅仅是想通过键盘按键来控制的话.比方进行第三人称视角控制,事实上仅仅须要进行简单的角度变换就可以.思路例如以下: 1.依照顺时针方向设定前.右 ...
- android 九宫格(16宫格)控件
public class NineRectView extends ViewGroup { private Context ctx; private int wSize,hSize,row,colum ...
- mysql设置远程訪问数据库的多种方法
问题:MySQL权限设置正确,但仍无法远程訪问.通过telnet发现3306port未打开. 分析:MySQL默认仅仅绑定127.0.0.1,即:仅仅有在本机才干訪问3306port. 解决:找到My ...
- Spring经常使用属性的注入及属性编辑器
对于对象的注入,我们使用ref方式,能够指定注入的对象.以下看下对于基本类型的注入.以及当spring无法转换基本类型进行注入时,怎样编写一个相似转换器的东西来完毕注入. 一.基本类型的注入 以下写一 ...
- 2015 Multi-University Training Contest 2 1006 Friends 壮压
题目链接 题意:t 组測试数据,每组測试数据有 n个人,m条关系 每条关系能够是 "线上关系" 或者 "线下关系". 要求每一个人的线上关系(条数) == 线下 ...
- 菜鸟nginx源代码剖析数据结构篇(九) 内存池ngx_pool_t
菜鸟nginx源代码剖析数据结构篇(九) 内存池ngx_pool_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csdn ...
- 用 C 语言编写一个简单的垃圾回收器
人们似乎觉得编写垃圾回收机制是非常难的,是一种仅仅有少数智者和Hans Boehm(et al)才干理解的高深魔法.我觉得编写垃圾回收最难的地方就是内存分配,这和阅读K&R所写的malloc例 ...
- Linux下配置httpd服务
第一步拷贝 cp /usr/local/apache2/bin/apachectl /etc/rc.d/init.d/httpd 第二步,修改 vim /etc/rc.d/init.d/httpd # ...
- 移动端H5页面编辑器开发实战--原理结构篇
很久前的写的文章了,转载下发到这里 原文地址: https://blog.csdn.net/tech_meizu/article/details/52288797