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

来源:互联网 发布:手机压缩文件解压软件 编辑:程序博客网 时间:2024/05/16 23:46

编程环境:

        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_OBJECTpublic:    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程序就介绍到这了。上面的框架可以直接使用哦~~~

      





0 0
原创粉丝点击