Qt+OpenGL聯合編程(1)


     最近發現了Qt在界面設計方面的優良性能,遂決定開始學習,奈何自己出身計算機圖形學專業,如能將它們結合起來自是最好啦。

     參考Nokia Developer網站上關於《如何在Qt中使用OpenGl》的文章,記錄下自己的實際使用過程。http://www.developer.nokia.com/Community/Wiki/%E5%A6%82%E4%BD%95%E5%9C%A8Qt%E4%B8%AD%E4%BD%BF%E7%94%A8OpenGL

同時也參考了tornadomeet的《OpenGL_Qt學習筆記之_01(創建一個OpenGL窗口)》http://www.cnblogs.com/tornadomeet/archive/2012/08/22/2651574.html

     OpenGL(Open Graphics Library)我就不多說了,它定義了一個跨編程語言、跨平台的編程接口的規格,用於生成二維、三維圖像。Qt主要通過QGLWidget這個類來實現,將opengl的函數和Qt的界面結合。所以一般開發opengl,同時要用到Qt的界面時,這些類都可以從QGLWidget繼承過來。

 


開發環境:windows 7+Qt 4.7.3+QtCreater 2.5.0

1.選擇工程類型時,選擇Qt Gui Application

2.進入Class Information界面時,此時基類可以選擇QMainWindow或者QWidget,因為后面還是要進行修改,所以這里差別不大。但是沒有試過QDialog,不知道情況怎么樣。

之后的實驗來自Nokia Developer


OpenGLQt.pro

為了使用QtOpenGL Module, 我們必須設.pro文件

QT       += core gui\
             opengl \\這里新加了一個opengl選項

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = BBSS_System_QT
TEMPLATE = app


SOURCES += main.cpp\
        openglqt.cpp

HEADERS  += openglqt.h

FORMS    += openglqt.ui

openglqt.h

ps: OpenGLQt類繼承於QGLWidget,主要是重寫了3個函數,initializeGL();paintGL();resizeGL();3個函數都是QGLWidget內部的虛函數。

#ifndef OPENGLQT_H
#define OPENGLQT_H

#include <QWidget>
#include <QtOpenGL>

namespace Ui {
class OpenGLQt;
}

class OpenGLQt : public QGLWidget
{
    Q_OBJECT
    
public:
    explicit OpenGLQt(QWidget *parent = 0);
    ~OpenGLQt();
    
private:
    Ui::OpenGLQt *ui;

protected:
void initializeGL(); void resizeGL(int width, int height); void paintGL(); void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);

private:
void draw();
int faceAtPosition(const QPoint &pos);
GLfloat rotationX;
GLfloat rotationY;
GLfloat rotationZ;
QColor faceColors[4];
QPoint lastPos;
void Spin(int xAngle, int yAngle, int zAngle);
 private slots:
 void Rotate();
};

#endif // OPENGLQT_H

openglqt.cpp

#include "openglqt.h"
#include "ui_openglqt.h"

OpenGLQt::OpenGLQt(QWidget *parent) :
    QGLWidget(parent),
    ui(new Ui::OpenGLQt)
{
    //QGLWidget::setFormat() to specify the OpenGL display context
       setFormat(QGLFormat(QGL::DoubleBuffer | QGL::DepthBuffer));
       rotationX = -21.0;
       rotationY = -57.0;
       rotationZ = 0.0;

       // Note: Square faces are set with static color and are cannot be changed during runtime
        // set the color of the faces of Tetrahedron
       faceColors[0] = Qt::red;
       faceColors[1] = Qt::green;
       faceColors[2] = Qt::blue;
       faceColors[3] = Qt::yellow;

       initializeGL();
       resizeGL(51,51);
       paintGL();

       //timer to spin the object
       QTimer *timer = new QTimer(this);
       connect(timer, SIGNAL(timeout()), this, SLOT(Rotate()));
       timer->start(20);
}

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

void OpenGLQt::initializeGL()
{
qglClearColor(Qt::black);
glShadeModel(GL_FLAT);   //設置陰影平滑模式
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
}

void OpenGLQt::resizeGL(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
GLfloat x = GLfloat(width) / height;
glFrustum(-x, x, -1.0, 1.0, 4.0, 15.0);
glMatrixMode(GL_MODELVIEW);
}

void OpenGLQt::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
draw();
}

void OpenGLQt::draw()
{

    //change the value if don't want to spin automatically and want to check the mouse event
   // glRotatef(rotationX/16.0f, 1.0, 0.0, 0.0); to glRotatef(rotationX, 1.0, 0.0, 0.0);
   // glRotatef(rotationY/16.0f, 0.0, 1.0, 0.0); to glRotatef(rotationY, 0.0, 1.0, 0.0);
    //glRotatef(rotationZ/16.0f, 0.0, 0.0, 1.0); to glRotatef(rotationZ, 0.0, 0.0, 1.0);


    // Draw Tetrahedron
    static const GLfloat P1[3] = { 0.0, -1.0, +2.0 };
    static const GLfloat P2[3] = { +1.73205081, -1.0, -1.0 };
    static const GLfloat P3[3] = { -1.73205081, -1.0, -1.0 };
    static const GLfloat P4[3] = { 0.0, +2.0, 0.0 };
    static const GLfloat * const coords[4][3] = {
    { P1, P2, P3 }, { P1, P3, P4 }, { P1, P4, P2 }, { P2, P4, P3 }
    };
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -10.0);
    glRotatef(rotationX/16.0f, 1.0, 0.0, 0.0);
    glRotatef(rotationY/16.0f, 0.0, 1.0, 0.0);
    glRotatef(rotationZ/16.0f, 0.0, 0.0, 1.0);
    for (int i = 0; i < 4; ++i) {
    glLoadName(i);
    glBegin(GL_TRIANGLES);
    qglColor(faceColors[i]);
    for (int j = 0; j < 3; ++j) {
    glVertex3f(coords[i][j][0], coords[i][j][1],
    coords[i][j][2]);
    }
    glEnd();
    }
}

void OpenGLQt::mousePressEvent(QMouseEvent *event)
{
lastPos = event->pos();
}

void OpenGLQt::mouseMoveEvent(QMouseEvent *event)
{
GLfloat dx = GLfloat(event->x() - lastPos.x()) / width();
GLfloat dy = GLfloat(event->y() - lastPos.y()) / height();
if (event->buttons() & Qt::LeftButton) {
rotationX += 180 * dy;
rotationY += 180 * dx;
updateGL();
}
else if (event->buttons() & Qt::RightButton)
{
rotationX += 180 * dy;
rotationZ += 180 * dx;
updateGL();
}
lastPos = event->pos();
}

void OpenGLQt::mouseDoubleClickEvent(QMouseEvent *event)
{
int face = faceAtPosition(event->pos());
if (face != -1) {
QColor color = QColorDialog::getColor(faceColors[face], this);
if (color.isValid()) {
faceColors[face] = color;
updateGL();
}
}
}

int OpenGLQt::faceAtPosition(const QPoint &pos)
{
const int MaxSize = 512;
GLuint buffer[MaxSize];
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
glSelectBuffer(MaxSize, buffer);
glRenderMode(GL_SELECT);
glInitNames();
glPushName(0);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPickMatrix(GLdouble(pos.x()), GLdouble(viewport[3] - pos.y()),
5.0, 5.0, viewport);
GLfloat x = GLfloat(width()) / height();
glFrustum(-x, x, -1.0, 1.0, 4.0, 15.0);
draw();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
if (!glRenderMode(GL_RENDER))
return -1;
return buffer[3];
}

void OpenGLQt::Rotate()
{
    //QMessageBox::about(this,"Hello","world");
      this->Spin(+2 * 16, +2 * 16, -1 * 16);
}
void OpenGLQt::Spin(int xAngle, int yAngle, int zAngle)
{
    rotationX += xAngle;
    rotationY += yAngle;
    rotationZ += zAngle;
    updateGL();
}
  1. 在構造函數中調用setFormat 設置OPENGL的顯示方式.
  2. 函數initializeGL()在paintGL()之前調用,且只調用一次,在這里可以設置OpenGL的顯示內容,定義顯示列表或者其他初始化操作。其中qglClearColor()是QGLWidget的函數,其他函數都是OpenGL標准函數。如果全部遵循OpenGL庫,可以調用RGBA格式的glClearColor()函數和顏色索引函數glClearIndex()。
  3. PaintGL() 函數將在任何需要重繪的時候調用,真正是在draw 函數中執行繪圖操作
  4. 在draw函數中我們繪制四面體
  5. Spin() 函數用於旋轉四面體到特定的角度

 

main.cpp

#include <QApplication>
#include "openglqt.h"
#include <iostream>
#include <QtOpenGL>
using namespace std;

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    if (!QGLFormat::hasOpenGL()) {
    cerr << "This system has no OpenGL support" << endl;
    return 1;
    }
    OpenGLQt openglqt;
    openglqt.setWindowTitle(QObject::tr("OpenGL Qt"));
    openglqt.resize(300, 300);
    openglqt.show();
    return a.exec();
}

運行結果

 


編譯和運行能夠正常,可是當關閉的時候就出現錯誤提示:"

ASSERT: "group->context() == q_ptr" in file .\qgl.cpp, line 1657

上網搜了一下這個問題,在http://blog.sina.com.cn/s/blog_404dab3b0101f2e5.html中找到了解決方案:

原來是現在的版本不能在構造函數里設置:

setFormat(QGLFormat(QGL::DoubleBuffer|QGL::DepthBuffer))

只要這樣設置就會在關閉程序的時候出錯。所以只有在構造函數的初始化列表里傳遞參數設置,比如:

OpenGLQt::OpenGLQt(QWidget *parent) :
    QGLWidget(QGLFormat(QGL::DoubleBuffer|QGL::DepthBuffer),parent),
    ui(new Ui::OpenGLQt){
......
}

 這樣果然在關閉程序的時候不會再拋出錯誤了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM