QT5 OpenGL (六, 键盘事件, 开关灯,放大缩小综合运用)

    • 概要
    • 实例效果图
      • 立体图放大图
      • 立体图缩小图
      • 不加矢量开灯图
      • 不加矢量关灯图
      • 加矢量关灯图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的方面, 正负,表示方向相反。

如果不加这个关灯后,就全暗了,加了之后就是确定光照在这个矢量方向上暗。

不知不觉写了之么多, 可能里面有一些理解有误的地方,希望大家多多指正。

时间: 2024-10-29 09:09:35

QT5 OpenGL (六, 键盘事件, 开关灯,放大缩小综合运用)的相关文章

页面上有一个div 100*100 颜色为黄色 按键盘上下左右键可以操作div移动 ctrl+键盘上下键可以放大缩小 ctrl+键盘左右键可以随机变颜色

1 <body> 2 <div id="w"> 3 <div class="n">按上键可以向上移动</div> 4 <div class="n">按下键可以向下移动</div> 5 <div class="n">按左键可以向左移动</div> 6 <div class="n">按右键可以向右移动&l

Javascript 事件对象(六)键盘事件

keyCode获取用户按下键盘的哪个按键 1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 5 <title>无标题文档</title> 6 <script> 7 /* 8 onkeydown : 当键盘按键按下的时候触发

【Unity 3D】学习笔记四十六:输入与控制——键盘事件

在游戏中,玩家控制主角移动,按键攻击,选择行走.都需要在程序中监听玩家的输入.unity为开发者提供了input库,来支持键盘事件,鼠标事件以及触摸事件.本文主要回顾键盘事件,以后会逐文复习鼠标以及触摸事件. 键盘事件 一般的PC键盘有104个不同的按键,在程序中通过监听这些按键事件,从而进一步执行逻辑操作.如:射击游戏中,W表示前进,S表示后退,A表示左移,D表示右移. 按下事件 在脚本中,用input.GetKeyDown( )方法将按键值作为参数,监听此按键是否被按下.按下返回true,否

MKMapView放大缩小事件

MKMapView放大缩小事件 by 伍雪颖 - (IBAction)mapZoomIn:(id)sender { MKCoordinateRegion region = _mapView.region; region.span.latitudeDelta=region.span.latitudeDelta * 0.4; region.span.longitudeDelta=region.span.longitudeDelta * 0.4; [_mapView setRegion:region

基于OpenGL编写一个简易的2D渲染框架-07 鼠标事件和键盘事件

这次为程序添加鼠标事件和键盘事件 当检测到鼠标事件和键盘事件的信息时,捕获其信息并将信息传送到需要信息的对象处理.为此,需要一个可以分派信息的对象,这个对象能够正确的把信息交到正确的对象. 实现思路: 要实现以上的功能,需要几个对象: 事件分派器:EventDispatcher,负责将 BaseEvent 分派给 EventListener 对象 事件监听器:EventListener,这只是一个接口类,接受 BaseEvent 的对象,真正的处理在它的子类中实现 事件:BaseEvent,储存

vue学习笔记(一)关于事件冒泡和键盘事件 以及与Angular的区别

一.事件冒泡 方法一.使用event.cancelBubble = true来组织冒泡 <div @click="show2()"> <input type="button" value="按钮" @click="show1($event)"> </div> methods:{ show1:function(ev){ console.log(ev); alert(1); ev.cancelB

UIButon 控件的尺寸放大缩小(也可以理解为图片的放大缩小,思路是一样的)-学习笔记

图片的放大缩小功能的简单实现(以一个简单的猜图项目中的放大缩小为例) 思路: 1.创建一个UIButton * guessimage  控件,设定好位置,再创建一个button bigImage控件测试一下 放大图片的方法 goToBig,同样放好位置: 2.给 guessimage 设置边距,尺寸大小,同样 bigImage 也进行设置等等: 3.给 bigImage 添加点击 放大图片的方法:goToBig, 在goToBig里面 定义 4个 座标的值,也就是 CGFloat guessim

广义mandelbrot集,使用python的matplotlib绘制,支持放大缩小

迭代公式的指数,使用的1+5j,这是个复数,所以是广义mandelbrot集,大家可以自行修改指数,得到其他图形.各种库安装不全的,自行想办法,可以在这个网站找到几乎所有的python库 http://www.lfd.uci.edu/~gohlke/pythonlibs/#matplotlib #encoding=utf-8 import numpy as np import pylab as pl import time from matplotlib import cm from math

基于jquery的鼠标滚动放大缩小图片

一直以来都想写一个图片放大和缩小的小玩意,本来以为会很复杂,这几天自己思考了一下,原来是so easy啊.目前实现的放大缩小,主要时依据鼠标的滚轮触发事件来实现的,废话少说直接上源码. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns