Qt5下利用freeglut实现最基本OpenGL程序(图文解释)

编程环境:

        Qt5.8.0 + Windows10(64bit) + freeglut

(Qt下载版本)


前言(可略过……):

        最近计算机图形学作业要求编写带下拉菜单栏menu的OpenGL程序,推荐用Qt,但也可以用MFC或者其他GUI库。但是据说Qt比 其他的使用起来更简单,所以下载了Qt。

        因为之前都是在VS2015下利用freeglut进行编程,转换到Qt平台下当然也希望能用freeglut(OpenGL1.0)编程,虽然Qt已经支持OpenGL3.0。但是网上貌似找不到Qt + freeglut的教程。另外,网上大部分教程、代码都是Qt4版本(在Qt5中,引入了QOpenGL*系列类,以取代Qt4时代的QGL*系列类),两个版本差别还是挺大的,用Qt4时代的QGL*系列类会报各种错。有些QOpenGL*系列类的教程也介绍得很不全面。简言之,就是,网上的教程参差不齐(我也花了两天时间才把下面这最简单的程序框架实现)。

        总之,下面实现的这份代码可以直接作为任何Qt下openGL程序的标准框架来使用。


程序基本功能:

        显示简单图形 + 能检测键盘、鼠标输入 + 下拉菜单选择不同功能

  


实现方法:

1、Qt下新建Qt Widgets Application项目,选择QMainWindow作为基类。创建好项目后,系统已经帮我们生成了mainwindow.h、mainwindow.cpp、main.cpp三份代码文件以及界面文件mainwindow.ui(用于设计)。在做菜单栏之前,前三份代码基本上都是不需要做什么修改的。


2、项目右键->添加新文件-> C++ -> C++ Class ->输入class name :如openglwindow。之后就会生成openglwindow.h、openglwindow.cpp,即我们用于编程的主要文件。

openglwindow.h :

#ifndef OPENGLWINDOW_H
#define OPENGLWINDOW_H

#include <QOpenGLWidget>
#include <QKeyEvent>
#include <QMouseEvent>

class openglwindow : public QOpenGLWidget {
    Q_OBJECT

public:
    openglwindow(QWidget *parent = 0);
    ~openglwindow();

    //用于菜单栏回调,改变方块颜色
    void changeColorGreen();
    void changeColorYellow();

protected:
    void initializeGL();
    void resizeGL(int width, int height);
    void paintGL();

    void keyPressEvent(QKeyEvent * e);    //需要先在.ui里面设置Widget的focusPolicy
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);

private:
    void drawQuads(int r, int g, int b);

    GLfloat eyeX, eyeY, eyeZ;    //摄像机位置
    GLfloat rotateAngle;         //正方体旋转角度

    int redChannel;
};

#endif // OPENGLWINDOW_H

openglwindow.cpp :

#include "openglwindow.h"
#include "iostream"
#include <gl/freeglut.h>
using namespace std;

float int2float(int intensity) {
    return (float)intensity / 255.0f;
}

openglwindow::openglwindow(QWidget *parent)
    :QOpenGLWidget(parent)
{
    rotateAngle = 0;
    eyeX = eyeY = eyeZ = 0.5f;

    redChannel = 0;
}

openglwindow::~openglwindow() {
}

void openglwindow::drawQuads(int r, int g, int b) {
    const GLfloat x1 = -0.05f, x2 = 0.05f;
    const GLfloat y1 = -0.05f, y2 = 0.05f;
    const GLfloat point[4][2] = { { x1,y1 },{ x1,y2 },{ x2,y2 },{ x2,y1 } };

    glColor3f(int2float(r), int2float(g), int2float(b));
    glBegin(GL_QUADS);
        for (int i = 0; i < 4; i++) {
            glVertex2fv(point[i]);
        }
    glEnd();
}

void openglwindow::initializeGL() {
    glClearColor( 0.0, 0.0, 0.0, 0.0 );
    glEnable( GL_DEPTH_TEST );

}

void openglwindow::paintGL() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glLoadIdentity();

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    gluLookAt(eyeX, eyeY, eyeZ, 0, 0, 0, 0, 1, 0);

    //front
    glPushMatrix();
    glTranslatef(-0.4f, 0, 0);
    drawQuads(redChannel, 255, 0);
    glPopMatrix();

    rotateAngle += 1.0f;
//    cout << "rotateAngle " << rotateAngle << endl;
    glRotatef(rotateAngle, 0, 1, 0);

    //front
    glPushMatrix();
    glTranslatef(0, 0, 0.05f);
    drawQuads(0, 255, 0);
    glPopMatrix();

    //behind
    glPushMatrix();
    glTranslatef(0, 0, -0.05f);
    drawQuads(255, 255, 0);
    glPopMatrix();

    //left
    glPushMatrix();
    glTranslatef(-0.05f, 0, 0);
    glRotatef(90, 0, 1, 0);
    drawQuads(0, 255, 255);
    glPopMatrix();

    //right
    glPushMatrix();
    glTranslatef(0.05f, 0, 0);
    glRotatef(270, 0, 1, 0);
    drawQuads(255, 0, 0);
    glPopMatrix();

    //top
    glPushMatrix();
    glTranslatef(0, 0.05f, 0);
    glRotatef(90, 1, 0, 0);
    drawQuads(0, 0, 255);
    glPopMatrix();

    //bottom
    glPushMatrix();
    glTranslatef(0, -0.05f, 0);
    glRotatef(270, 1, 0, 0);
    drawQuads(255, 0, 255);
    glPopMatrix();

    //repaint
    update();

}

void openglwindow::resizeGL(int width, int height) {
    if ( height == 0 )
        height = 1;

    glViewport( 0, 0, (GLint)width, (GLint)height );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    gluPerspective( 45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0 );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
}

void openglwindow::keyPressEvent(QKeyEvent * e) {
    switch (e->key()) {
        case Qt::Key_W:
            cout << "w" << endl;
            break;
        case Qt::Key_A:
            cout << "a" << endl;
            break;
        case Qt::Key_S:
            cout << "s" << endl;
            break;
        case Qt::Key_D:
            cout << "d" << endl;
            break;
        default:
            break;
    }
}

void openglwindow::mousePressEvent(QMouseEvent *event) {
    if (event->buttons() == Qt::LeftButton) {
        cout << "LeftButton mousePos (" << event->pos().x() << ", " << event->pos().y() << ")" << endl;
    }
    else if (event->buttons() & Qt::RightButton) {
        cout << "RightButton mousePos (" << event->pos().x() << ", " << event->pos().y() << ")" << endl;

    }

}

void openglwindow::mouseMoveEvent(QMouseEvent *event) {

}

void openglwindow::mouseReleaseEvent(QMouseEvent *event) {

}

void openglwindow::changeColorGreen() {
    cout << "###### change Color Green!" << endl;
    redChannel = 0;
}

void openglwindow::changeColorYellow() {
    cout << "###### change Color Yellow!" << endl;
    redChannel = 255;
}
        相信有过freeglut编程的同学,认真看下代码也能大概搞清怎么写的了。

        (1)简单图形显示:主要是initializeGL(); resizeGL(int width, int height); paintGL(); 三个函数。应该不用多说了,逻辑跟普通的OpenGL程序类似,但有一点是paintGL()里面调用了update()方法,为重新绘制。由于代码是让正方体绕y轴自动旋转,如果不加update()会静止不动,update()为重新绘制场景(旋转角时刻改变)。

        (2)检测键盘、鼠标输入:即keyPressEvent(QKeyEvent * e) 、mousePressEvent(QMouseEvent *event) 那4个方法(注意include的头文件)。这几个方法也不难理解,逻辑也跟普通的OpenGL程序类似。

        (3)下拉菜单选择不同功能:这个在下面说了ui界面之后再回头说。


3、有了这两份代码,还不能直接跑!需要在mainwindow.ui给程序设置一个显示窗口:
        双击mainwindow.ui -> 左边的空间栏找到Widget,拖到设计界面,设置大小。

        此时我们发现右边栏,centralWidget下多了一个子widget:

        

        在widget上右键,提升为/提升的窗口部件 -> 输入类名称openglwindow -> 添加、提升:

          

        看到widget那一行改成openglwindow 名字,即为提升成功。


        此时,运行程序。应该就能看到图形了!


4、不过,此时是不是发现鼠标、键盘没响应?

        由于在Qt下,widget只有获取焦点focus才能响应鼠标、键盘事件。我们回到.ui文件,点击上面的widget,看右下方属性栏,发现focusPolicy一栏为NoFocus,从这就可以知道原因了。点击,改为ClickFocus,保存,运行。就能检测到两种事件了:

        


5、最后为下拉菜单:

        (1)先还是在界面文件内,可以看到中间设计界面上方,有个“在这里输入”按钮,就可以编辑菜单啦:

            

        (2)做成上面这样的时候,可以看到右边栏,已经在menuBar下生产子menu了:

            


6、问题来了,怎么能让点击的菜单按钮跟代码方法连接起来呢?

        从上面的openglwindow.h、openglwindow.cpp我们可以看到两个方法void changeColorGreen();   void changeColorYellow(); 也就是改变颜色,这个好写。还记得我上面说了,做菜单栏之前,mainwindow.h、mainwindow.cpp、main.cpp三份代码基本上不需要做什么修改。但是若要加菜单栏,就需要在这几个文件做文章了。(其实main.cpp也没做什么改动

main.cpp :

#include "mainwindow.h"
#include "openglwindow.h"
#include <QApplication>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    a.setApplicationName("My First openGL Widget");

    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.h :

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow {
    Q_OBJECT

    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();

    private slots:
        void changeColorGreen();
        void changeColorYellow();

    private:
        Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp :

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);


    connect(ui->actionGreen_2, SIGNAL(triggered()), this, SLOT(changeColorGreen()));
    connect(ui->actionYellow_2, SIGNAL(triggered()), this, SLOT(changeColorYellow()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::changeColorGreen() {
    ui->widget->changeColorGreen();
}

void MainWindow::changeColorYellow() {
    ui->widget->changeColorYellow();
}

        改动的地方就是在.h文件了加了private slots两个方法,在.cpp文件里实现两个方法,并且用connect方法做连接(具体用法, 请鼠标靠近函数名按F1查看)。我们可以看到actionGreen_2、actionYellow_2、widget三个都是在ui文件里 几个对象的名称

    

        好了,连接做好了,运行点击试试看~~~


7、最后放上整个项目文件结构:

    

        但是值得一提的是,点击上面的“项目”,选择文件系统,会发现有个ui_mainwindow.h文件(mainwindow.cpp会include),可以点开研究下,对整个窗口、菜单之间串联连接会有更深理解的。


        好了,关于Qt的OpenGL程序就介绍到这了。上面的框架可以直接使用哦~~~

      





评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值