• Qt OpenGL 旋转


    这次教程中,我们将在第03课的基础上,教大家如何旋转三角形和四边形。我们将让三角形沿y轴旋转,四边形沿x轴旋转,最终我们能得到一个三角形和四边形自动旋转的场景。

    程序运行时效果如下:

    下面进入教程:

    首先打开myglwidget.h文件,我们需要增加两个变量来控制这两个对象的旋转。这两个变量加在类的私有声明处,将类声明更改如下:

     1 #ifndef MYGLWIDGET_H
     2 #define MYGLWIDGET_H
     3  
     4 #include <QWidget>
     5 #include <QGLWidget>
     6  
     7 class MyGLWidget : public QGLWidget
     8 {
     9     Q_OBJECT
    10 public:
    11     explicit MyGLWidget(QWidget *parent = 0);
    12     ~MyGLWidget();
    13  
    14 protected:
    15     //对3个纯虚函数的重定义
    16     void initializeGL();
    17     void resizeGL(int w, int h);
    18     void paintGL();
    19  
    20     void keyPressEvent(QKeyEvent *event);           //处理键盘按下事件
    21  
    22 private:
    23     bool fullscreen;                                //是否全屏显示
    24     
    25     GLfloat m_rtri;                                 //控制三角形的角度
    26     GLfloat m_rquad;                                //控制四边形的角度
    27 };
    28  
    29 #endif // MYGLWIDGET_H

    我们增加了两个浮点类型的变量,使得我们能够非常精确地旋转对象,你渐渐会发现浮点数是OpenGL编程的基础。新变量中叫做m_rtri的用来旋转三角形,m_rquad旋转四边形。

    接下来,我们需要打开myglwidget.cpp,在构造函数中对两个新变量进行初始化,这部分很简单,不作过多解释,代码如下:

    1 MyGLWidget::MyGLWidget(QWidget *parent) :
    2     QGLWidget(parent)
    3 {
    4     fullscreen = false;    
    5     m_rtri = 0.0f;
    6     m_rquad = 0.0f;
    7 }

    然后进入重点的paintGL()函数了,我们只需在第03课代码的基础上,做一定的修改,就能实现三角形和四边形的旋转了。

    下面我将重写整个paintGL()函数,具体代码如下:

     1 void MyGLWidget::paintGL()                              //从这里开始进行所以的绘制
     2 {
     3     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除屏幕和深度缓存
     4     glLoadIdentity();                                   //重置当前的模型观察矩阵
     5  
     6     glTranslatef(-1.5f, 0.0f, -6.0f);                   //左移1.5单位,并移入屏幕6.0单位
     7     glRotatef(m_rtri, 0.0f, 1.0f, 0.0f);                //绕y轴旋转三角形
     8     glBegin(GL_TRIANGLES);                              //开始绘制三角形
     9         glColor3f(1.0f, 0.0f, 0.0f);                    //设置当前色为红色
    10         glVertex3f(0.0f, 1.0f, 0.0f);                   //上顶点
    11         glColor3f(0.0f, 1.0f, 0.0f);                    //设置当前色为绿色
    12         glVertex3f(-1.0f, -1.0f, 0.0f);                 //左下
    13         glColor3f(0.0f, 0.0f, 1.0f);                    //设置当前色为蓝色
    14         glVertex3f(1.0f, -1.0f, 0.0f);                  //右下
    15     glEnd();                                            //三角形绘制结束
    16  
    17     glLoadIdentity();                                   //重置模型观察矩阵
    18     glTranslatef(1.5f, 0.0f, -6.0f);                    //右移1.5单位,并移入屏幕6.0单位
    19     glRotatef(m_rquad, 1.0f, 0.0f, 0.0f);               //绕x轴旋转四边形
    20     glColor3f(0.5f, 0.5f, 1.0f);                        //一次性将当前色设置为蓝色
    21     glBegin(GL_QUADS);                                  //开始绘制四边形
    22         glVertex3f(-1.0f, 1.0f, 0.0f);                  //左上
    23         glVertex3f(1.0f, 1.0f, 0.0f);                   //右上
    24         glVertex3f(1.0f, -1.0f, 0.0f);                  //左下
    25         glVertex3f(-1.0f, -1.0f, 0.0f);                 //右下
    26     glEnd();                                            //四边形绘制结束
    27  
    28     m_rtri += 0.5f;                                     //增加三角形的旋转变量
    29     m_rquad -= 0.5f;                                    //减少四边形的旋转变量
    30 }

    上面的代码绘制三角形时多了一新函数glRotatef(Angle, Xvector, Yvector, Zvector)。该函数负责让对象绕某个轴旋转,这个函数有诸多用处。Angle通常是个变量代表对象转过的角度,后三个参数则共同决定旋转轴的方向。故(1.0f, 0.0f, 0.0f)、(0.0f, 1.0f, 0.0f)、(0.0f, 0.0f, 1.0f)表示依次绕x、y、z轴旋转,参照此原理,我们也能实现四边形的旋转。

    我们会发现画完三角形后,相比原来的代码多了一行glLoadIdentity(),目的是为了重置模型观察矩阵。如果我们没有重置,直接调用glTranslate的话,会发现可能没有朝着我们所希望的方向旋转,这是由于坐标轴以前已经旋转了。所以我们本来要左右移动对象的,可能就变成上下移动了。还不理解的朋友可以试着将glLoadIdentity()试注释掉之后,看会出现什么结果。

    重置模型观察矩阵之后,x、y、z轴都复位,我们调用glTranslate时只向右移动了1.5单位,而不是之前的3.0单位。因为我们重置场景的时候,焦点又回到了场景的中心,这样只需右移单位即可。

    最后我们通过增加m_rtri和减少m_rquad使得物体自己旋转起来,我们可以尝试改变代码中的+和-,来体会对象旋转的方向是如何改变的。并尝试着将0.5改成4.0,。这个数字越大,物体就转得越快,这个数字越小,物体转的就越慢。

    至此,我们似乎已经完成了,但是运行程序时发现,三角形和四边形并没有自动旋转起来。这是由于paintGL()被调用一次之后,没有发生其他的事件使得它被自动调用。我们可以通过拉伸窗口的大小,发现三角形和四边形就动起来了,这是由于我们改变了窗口大小,调用了reszieGL()之后紧接着调用了paintGL()对场景进行重绘。显然,我们不能一直通过拉伸窗口来实现旋转,这样显得很拙,我们可以在构造函数中利用Qt的定时器事件来控制paintGL()的调用。先在myglwidget.cpp中添加头文件#include <QTimer>。构造函数代码如下:(具体initializeGL()、reszieGL()、paintGL()的调用情况请参见)

     1 MyGLWidget::MyGLWidget(QWidget *parent) :
     2     QGLWidget(parent)
     3 {
     4     fullscreen = false;
     5     m_rtri = 0.0f;
     6     m_rquad = 0.0f;
     7  
     8     QTimer *timer = new QTimer(this);                   //创建一个定时器
     9     //将定时器的计时信号与updateGL()绑定
    10     connect(timer, SIGNAL(timeout()), this, SLOT(updateGL()));
    11     timer->start(10);                                   //以10ms为一个计时周期
    12 }

    这里将定时器的timeout()信号与updateGL()槽绑定,每过10ms就会调用一次updateGL(),而updateGL()调用后会调用paintGL()对场景进行重绘,这样就通过对场景不停地重绘实现对象的旋转。(对Qt定时器不了解的朋友请先百度了解下其机制)
    现在就可以运行程序看效果了!

  • 相关阅读:
    java学习笔记4对象的初始化与回收
    java学习笔记2数据类型、数组
    java学习笔记3类与对象的基础
    java学习笔记5类的方法
    java学习笔记1开发环境平台总结
    BZOJ 4843
    SPOJ TTM
    BZOJ 4154
    POJ 3680
    半平面交模板 HDU 1469
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/14047943.html
Copyright © 2020-2023  润新知