Qt学习:三维绘图之OpenGL和Qt的结合

        OpenGL是绘制三维图形的标准API。Qt应用程序可以使用QtOpenGL模块绘制三维图形,该模块依赖于系统的OpenGL库。Qt OpenGL模块提供QGLWidget类,可以通过对它子类化,并使用OpenGL命令开发出自己的窗口部件。对许多三维应用程序来说,这就足够了。
        这节假设大家都已经学过OpenGL,这样我们就无后顾之忧了。
        在Qt中绘制OpenGL通常需要做以下工作:1)、必须子类化QGLWidget;2)、实现几个虚函数:void initiallizeGL()
void resizeGL(), void paintGL(), 这些都是在QGLWidget中实现的,还有一些和用户交互的虚函数,诸如void mouseMoveEvent()之类的,想必大家都比较熟了,这些虚函数是在Widget中实现的。 
        下面我们介绍一个例子。先给出该程序的效果:

 

        菜单栏里的第一项可以完成一个自定义大小的抓图,即由用户自己决定抓图的大小,抓图会显示在右侧的方框里,注意这里只能设置图形的大小小雨当前图形的尺寸, 如果大于当前图形尺寸,则钳位到当前图形尺寸。效果看起来应该是这样:

 

        菜单栏第二项也是一个抓图功能,它返回一个当前图形尺寸的图形,并填充到右侧。
        第三项即清除右侧图形。 

        这个代码由以下部件构成:
        一个QMainWindow,我们通过子类化这个类来完成自己想要的一些功能。
        一个QWidget,我们把它作为中央窗口,在其上添加自己想要的一些子部件。
        两个QScrollBar,用来盛载一个QGLWidget和一个QLabel。
        一个QGLWidget,我们通过子类化它并把它加进一个QScrollBar来实现三维绘图,即上图所示的左边窗口。
        一个QLabel,同样,我们把这个QLabel加进一个QScrollBar来接收抓图后的显示效果。
        三个QSlider,我们通过这三个滑动条控制所绘制的四面体沿x,y,z轴转动,同样鼠标拖动这个四面体也可以改变滑动条的值。
        以上是整个程序的框架。
        以下是代码的实现部分。

        MainWindow 类定义了我们整个程序的框架:

//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

class QAction;
class QLabel;
class QMenu;
class QSlider;
class QScrollArea;

class GLWidget;

class MainWindow : public QMainWindow
{
    Q_OBJECT
    
public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void renderIntoPixmap();
    void grabFrameBuffer();
    void clearPixmap();
    void about();

private:

    void createMenus();
    void createActions();

    QSlider *createSlider(const char *changedSignal, const char *setterSlot);
    void setPixmap(const QPixmap &pixmap);
    QSize getSize();

    QWidget *centralWidget;
    QScrollArea *glWidgetArea;
    QScrollArea *pixmapLabelArea;
    GLWidget *glWidget;
    QLabel *pixmapLabel;
    QSlider *xSlider;
    QSlider *ySlider;
    QSlider *zSlider;

    QMenu *fileMenu;
    QMenu *helpMenu;
    QAction *renderIntoPixmapAction;
    QAction *grabFrameBufferAction;
    QAction *clearPixmapAction;
    QAction *exitAction;
    QAction *aboutAction;
    QAction *aboutQtAction;

};

#endif // MAINWINDOW_H


 

        以下是程序的实现部分:

//mainwindow.cpp
#include <QtOpenGL>
#include <QAction>
#include <QLabel>
#include <QMenu>
#include <QSlider>
#include <QScrollArea>
#include <QMenuBar>
#include <QApplication>


#include "mainwindow.h"
#include "glwidget.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    centralWidget = new QWidget;
    setCentralWidget(centralWidget);

    glWidget = new GLWidget;
    pixmapLabel = new QLabel;

    glWidgetArea = new QScrollArea;
    glWidgetArea->setWidget(glWidget);
    //glWidgetArea->viewport()->setBackgroundRole(QPalette::Dark);
    glWidgetArea->setWidgetResizable(true);
    glWidgetArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    glWidgetArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    glWidgetArea->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
    glWidgetArea->setMinimumSize(50, 50);

    pixmapLabelArea = new QScrollArea;
    pixmapLabelArea->setWidget(pixmapLabel);
    pixmapLabelArea->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
    pixmapLabelArea->setMinimumSize(50, 50);

    //在构造一个QSlider时将QGLWidget的信号和槽传给这个函数的形参,这样就可以在QMainWindow中
    //控制OpenGL的动作了,而让GLWidget类只完成绘图工作。
    xSlider = createSlider(SIGNAL(xRotationChanged(int)),
                           SLOT(setXRotation(int)));
    ySlider = createSlider(SIGNAL(yRotationChanged(int)),
                           SLOT(setYRotation(int)));
    zSlider = createSlider(SIGNAL(zRotationChanged(int)),
                           SLOT(setZRotation(int)));

    /*
    xSlider = new QSlider(Qt::Horizontal);
    ySlider = new QSlider(Qt::Horizontal);
    zSlider = new QSlider(Qt::Horizontal);
    */

    QGridLayout *centralLayout = new QGridLayout;
    centralLayout->addWidget(glWidgetArea, 0, 0);
    centralLayout->addWidget(pixmapLabelArea, 0, 1);
    centralLayout->addWidget(xSlider, 1, 0, 1, 2);
    centralLayout->addWidget(ySlider, 2, 0, 1, 2);
    centralLayout->addWidget(zSlider, 3, 0, 1, 2);
    centralWidget->setLayout(centralLayout);

    createActions();
    createMenus();

    xSlider->setValue(15 * 16);
    ySlider->setValue(345 * 16);
    zSlider->setValue(0 * 16);

    setWindowTitle(tr("Grabeer"));
    resize(480, 360);
}

void MainWindow::setPixmap(const QPixmap &pixmap)
{
    pixmapLabel->setPixmap(pixmap);
    QSize size = pixmap.size();
    if (size - QSize(1, 0) == pixmapLabelArea->maximumViewportSize())
        size -= QSize(1, 0);
    pixmapLabel->resize(size);
}

QSize MainWindow::getSize()
{
    bool ok;
    QString text = QInputDialog::getText(this, tr("Grabber"),
                                         tr("Enter Pixmap Size:"),
                                         QLineEdit::Normal,
                                         tr("%1 x %2").arg(glWidget->width())
                                                      .arg(glWidget->height()),
                                         &ok);
    if (!ok)
        return QSize();

    QRegExp regExp(tr("([0-9]+) *x *([0-9]+)"));
    if (regExp.exactMatch(text)) {
        int width = regExp.cap(1).toInt();
        int height = regExp.cap(2).toInt();
        if (width > 0 && width < 2048 && height > 0 && height < 2048)
             return QSize(width, height);
    }
    return glWidget->size();
}

void MainWindow::renderIntoPixmap()
{
    QSize size = getSize();
    if (size.isValid()) {
        QPixmap pixmap = glWidget->renderPixmap(size.width(), size.height());
        setPixmap(pixmap);
    }
}

void MainWindow::grabFrameBuffer()
{
    //QGLWidget有一个返回其帧缓冲区的QImage图片的函数
    QImage image = glWidget->grabFrameBuffer();
    //QPixmap的fromImage函数把一个QImage转换成QPixmap
    setPixmap(QPixmap::fromImage(image));
}

void MainWindow::clearPixmap()
{
    setPixmap(QPixmap()); //给它传一个空的对象
}

void MainWindow::about()
{
    QMessageBox::about(this, tr("About Grabber"),
             tr("The <b>Grabber</b> example demonstrates two approaches for "
                "rendering OpenGL into a Qt pixmap."));
}

QSlider *MainWindow::createSlider(const char *changedSignal,
                                  const char *setterSlot)
{
    QSlider *slider = new QSlider(Qt::Horizontal);
    slider->setRange(0, 16 * 360);
    slider->setSingleStep(16);
    slider->setPageStep(15 * 16);
    slider->setTickInterval(15 * 16);
    slider->setTickPosition(QSlider::TicksRight);

    //这种经典的用法一定要小心,报错:glWidget的槽函数在传进来的时候已经被强制转换成SLOT了,
    //所以setterSlot不用SLOT修饰;同样,changedSignal也不能再拿SIGNAL修饰
    connect(slider, SIGNAL(valueChanged(int)), glWidget, setterSlot);
    connect(glWidget, changedSignal, slider, SLOT(setValue(int)));

    return slider;
}

void MainWindow::createActions()
{
    renderIntoPixmapAction = new QAction(tr("&Render into Pixmap..."), this);
    renderIntoPixmapAction->setShortcut(tr("Ctrl+R"));
    renderIntoPixmapAction->setToolTip(tr("yes, triggerd it"));
    connect(renderIntoPixmapAction, SIGNAL(triggered()),
            this, SLOT(renderIntoPixmap()));

    grabFrameBufferAction = new QAction(tr("&Grab Frame Buffer"), this);
    grabFrameBufferAction->setShortcut(tr("Ctrl+G"));
    connect(grabFrameBufferAction, SIGNAL(triggered()),
            this, SLOT(grabFrameBuffer()));

    clearPixmapAction = new QAction(tr("&Clear Pixmap"), this);
    clearPixmapAction->setShortcut(tr("Ctrl+L"));
    connect(clearPixmapAction, SIGNAL(triggered()), this, SLOT(clearPixmap()));

    exitAction = new QAction(tr("E&xit"), this);
    exitAction->setShortcuts(QKeySequence::Quit);
    connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));

    aboutAction = new QAction(tr("&About"), this);
    connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));

    aboutQtAction = new QAction(tr("About &Qt"), this);
    connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}

void MainWindow::createMenus()
{
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(renderIntoPixmapAction);
    fileMenu->addAction(grabFrameBufferAction);
    fileMenu->addAction(clearPixmapAction);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAction);

    helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(aboutAction);
    helpMenu->addAction(aboutQtAction);
}

MainWindow::~MainWindow()
{ 
}

 

        GLWidget类是整个绘图的部分,在这部分虽然用了一点Qt的东西,但我们不是非要这样使用,我们可以用整个纯净的OpengGL库来完成我们的绘制。

//glwidget.h
#ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QGLWidget>

class GLWidget : public QGLWidget
{
    Q_OBJECT

public:
    explicit GLWidget(QWidget *parent = 0);

    int xRotation() const { return xRot; }
    int yRotation() const { return yRot; }
    int zRotation() const { return zRot; }

signals:
    void xRotationChanged(int angle);
    void yRotationChanged(int angle);
    void zRotationChanged(int angle);
    
public slots:
    void setXRotation(int angle);
    void setYRotation(int angle);
    void setZRotation(int angle);

protected:
    void initializeGL();
    void paintGL();
    void resizeGL(int w, int h);
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);

private slots:
    void alwaysRotate();
    void drawTriangle();

private:
    void normalizeAngle(int *angle);

    int xRot;
    int yRot;
    int zRot;

    QColor faceColors[4];
    QPoint lastPos;
};

#endif // GLWIDGET_H

        以下是代码实现部分:

//glwidget.cpp
#include <QtGui>
#include <QtOpenGL>

#include <math.h>

#include "glwidget.h"

GLWidget::GLWidget(QWidget *parent) :
    QGLWidget(parent)
{
    xRot = 0;
    yRot = 0;
    zRot = 0;

    faceColors[0] = Qt::red;
    faceColors[1] = Qt::green;
    faceColors[2] = Qt::blue;
    faceColors[3] = Qt::yellow;

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(alwaysRotate()));
    timer->start(70);
}

void GLWidget::initializeGL()
{
    glClearColor(0.0, 0.2, 0.3, 1.0);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_DEPTH);
}

void GLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glPushMatrix();
    drawTriangle();
    glPopMatrix();
}

void GLWidget::resizeGL(int w, int h)
{
    int side = qMin(w, h);
    glViewport((width() - side) / 2, (height() - side) / 2, side, side);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-1.2, 1.2, -1.2, 1.2, 5.0, 60.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -40.0);
}

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

void GLWidget::mouseMoveEvent(QMouseEvent *event)
{
    int dx = event->x() - lastPos.x();
    int dy = event->y() - lastPos.y();

    if (event->buttons() & Qt::LeftButton) {
        (xRot + 4 * dx);
        setYRotation(yRot + 4 * dy);
    } else if (event->buttons() & Qt::RightButton) {
        (xRot + 4 * dy);
        setZRotation(zRot + 4 * dx);
    }

    lastPos = event->pos();
}

void GLWidget::drawTriangle()
{
    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(xRot, 1.0, 0.0, 0.0);
    glRotatef(yRot, 0.0, 1.0, 0.0);
    glRotatef(zRot, 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 GLWidget::normalizeAngle(int *angle)
{
    while (*angle < 0)
        angle += 360 * 16;
    while (*angle > 360 *16)
        angle -= 360 *16;
}

void GLWidget::setXRotation(int angle)
{
    normalizeAngle(&angle);
    if ( angle != xRot ) {
        xRot = angle;
        emit xRotationChanged(angle);
        updateGL();
    }
}

void GLWidget::setYRotation(int angle)
{
    normalizeAngle(&angle);
    if ( angle != yRot ) {
        yRot = angle;
        emit yRotationChanged(angle);
        updateGL();
    }
}

void GLWidget::setZRotation(int angle)
{
    normalizeAngle(&angle);
    if ( angle != zRot ) {
        zRot = angle;
        emit zRotationChanged(angle);
        updateGL();
    }
}

void GLWidget::alwaysRotate()
{
    zRot += 2;
    emit zRotationChanged(zRot);
    updateGL();
}


 

         至此,我们就完成了整个应用程序的编写,继续努力。

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 10
    点赞
  • 91
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
### 回答1: Qt和Halcon都是现代计算机视觉领域中广泛使用的工具集。Qt是一种软件开发框架,提供了GUI编程、网络编程、多线程编程等工具;而Halcon是一个图像处理库,提供了各种图像分析和机器视觉的工具。 在三维显示方面,Qt提供了一些3D绘图函数,可以用于绘制三维图像和场景。而Halcon在三维显示方面比较擅长于提供点云数据可视化功能。在三维显示场景的过程中,Halcon可以读取和处理3D数据,如点云、深度图、体数据等,并对其进行可视化。 结合使用Qt和Halcon可以实现更加灵活和高效的三维数据可视化,例如在Qt中利用Halcon提供的函数来进行点云可视化和场景重建。同时,Qt的渲染功能和交互性非常强大,可以方便地完成用户界面的设计,以及与用户进行交互。 总之,Qt和Halcon在三维显示方面都有各自的优势,结合使用可以为用户提供更好的三维数据可视化体验。 ### 回答2: qt halcon三维显示是指使用QT编程语言和Halcon三维函数库,进行三维模型的显示和处理。Halcon三维函数库提供了强大的三维图像处理和分析能力,包括三维形状分析、三维重构、三维点云处理等功能。而QT是一种流行的跨平台应用程序开发框架,能够帮助开发者快速构建图形用户界面和多种应用。 使用qt halcon三维显示的优势在于可以对三维模型进行高效、精确的处理和显示。开发者可以通过QT提供的图形界面,方便地将Halcon三维函数库的功能整合到自己的应用中。此外,QT还提供了强大的图形渲染引擎,可以对复杂的三维模型进行实时渲染和交互操作。 qt halcon三维显示的应用领域非常广泛,包括机器人视觉、医疗影像、产品设计和制造等。例如,在机器人视觉领域,qt halcon三维显示可以帮助开发者快速构建拍摄、识别、定位和抓取等功能,提高机器人的智能水平。在医疗影像领域,qt halcon三维显示可以帮助医生更加直观地显示患者的CT、MRI等影像,帮助诊断疾病。在产品设计和制造领域,开发者可以使用qt halcon三维显示显示和编辑三维模型,帮助设计和制造出更加精确、完美的产品。 综上所述,qt halcon三维显示是一种强大、高效的三维模型显示和处理方案,可以帮助开发者在各个领域提升应用的智能和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值