Qt 中嵌套 OSG 窗口(两种思路带源码)

说明


  • 网上大部分操作介绍都讲得很繁琐,并且编译未必能过
  • 经我全网搜索与测试,最终总结出以下两种方法,两种方法均编译通过且完整运行

方法一:继承于 QOpenGLWidget


链接直达

Step-by-step on how to set up your CMake, Qt and OSG in draw-on-demand mode(分为1和2)两个部分

源码(就一个 main.cpp)

/*
 * =====================================================================================
 *
 *       Filename:  main.cpp
 *
 *    Description: Minimalistic project example that uses both Qt and OpenSceneGraph libraries.
 *
 *        Version:  1.0
 *        Created:  30-Jun-16 10:23:06 AM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Victoria Rudakova (vicrucann@gmail.com),
 *   Organization:  vicrucann.github.io
 *
 * =====================================================================================
 */
#include <stdlib.h>
#include <stdio.h>
#include <iostream>

#include <QApplication>
#include <QMainWindow>
#include <QOpenGLWidget>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QDesktopWidget>
#include <QScreen>
#include <QtGlobal>
#include <QWindow>

#include <osg/ref_ptr>
#include <osgViewer/GraphicsWindow>
#include <osgViewer/Viewer>
#include <osg/Camera>
#include <osg/ShapeDrawable>
#include <osg/StateSet>
#include <osg/Material>
#include <osgGA/EventQueue>
#include <osgGA/TrackballManipulator>


class QtOSGWidget : public QOpenGLWidget {
public:
    QtOSGWidget(QWidget *parent = 0)
        : QOpenGLWidget(parent)
        , _mGraphicsWindow(new osgViewer::GraphicsWindowEmbedded( this->x(), this->y(),
                           this->width(), this->height() ) )
        , _mViewer(new osgViewer::Viewer)
          // take care of HDPI screen, e.g. Retina display on Mac
        , m_scale(QApplication::desktop()->devicePixelRatio()) {
        osg::Cylinder *cylinder    = new osg::Cylinder( osg::Vec3( 0.f, 0.f, 0.f ), 0.25f, 0.5f );
        osg::ShapeDrawable *sd = new osg::ShapeDrawable( cylinder );
        sd->setColor( osg::Vec4( 0.8f, 0.5f, 0.2f, 1.f ) );
        osg::Geode *geode = new osg::Geode;
        geode->addDrawable(sd);

        osg::Camera *camera = new osg::Camera;
        camera->setViewport( 0, 0, this->width(), this->height() );
        camera->setClearColor( osg::Vec4( 0.9f, 0.9f, 1.f, 1.f ) );
        float aspectRatio = static_cast<float>( this->width()) / static_cast<float>( this->height() );
        camera->setProjectionMatrixAsPerspective( 30.f, aspectRatio, 1.f, 1000.f );
        camera->setGraphicsContext( _mGraphicsWindow );

        _mViewer->setCamera(camera);
        _mViewer->setSceneData(geode);
        osgGA::TrackballManipulator *manipulator = new osgGA::TrackballManipulator;
        manipulator->setAllowThrow( false );
        this->setMouseTracking(true);
        _mViewer->setCameraManipulator(manipulator);
        _mViewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
        _mViewer->realize();
    }


    virtual ~QtOSGWidget() {}

protected:

    virtual void paintGL() {
        _mViewer->frame();
    }

    virtual void resizeGL( int width, int height ) {
        this->getEventQueue()->windowResize(this->x()*m_scale, this->y() * m_scale, width * m_scale, height * m_scale);
        _mGraphicsWindow->resized(this->x()*m_scale, this->y() * m_scale, width * m_scale, height * m_scale);
        osg::Camera *camera = _mViewer->getCamera();
        camera->setViewport(0, 0, this->width()*m_scale, this->height()* m_scale);
    }

    virtual void initializeGL() {
        osg::Geode *geode = dynamic_cast<osg::Geode *>(_mViewer->getSceneData());
        osg::StateSet *stateSet = geode->getOrCreateStateSet();
        osg::Material *material = new osg::Material;
        material->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE );
        stateSet->setAttributeAndModes( material, osg::StateAttribute::ON );
        stateSet->setMode( GL_DEPTH_TEST, osg::StateAttribute::ON );
    }

    virtual void mouseMoveEvent(QMouseEvent *event) {
        this->getEventQueue()->mouseMotion(event->x()*m_scale, event->y()*m_scale);
    }

    virtual void mousePressEvent(QMouseEvent *event) {
        unsigned int button = 0;
        switch (event->button()) {
        case Qt::LeftButton:
            button = 1;
            break;
        case Qt::MiddleButton:
            button = 2;
            break;
        case Qt::RightButton:
            button = 3;
            break;
        default:
            break;
        }
        this->getEventQueue()->mouseButtonPress(event->x()*m_scale, event->y()*m_scale, button);
    }

    virtual void mouseReleaseEvent(QMouseEvent *event) {
        unsigned int button = 0;
        switch (event->button()) {
        case Qt::LeftButton:
            button = 1;
            break;
        case Qt::MiddleButton:
            button = 2;
            break;
        case Qt::RightButton:
            button = 3;
            break;
        default:
            break;
        }
        this->getEventQueue()->mouseButtonRelease(event->x()*m_scale, event->y()*m_scale, button);
    }

    virtual void wheelEvent(QWheelEvent *event) {
        int delta = event->delta();
        osgGA::GUIEventAdapter::ScrollingMotion motion = delta > 0 ?
                osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN;
        this->getEventQueue()->mouseScroll(motion);
    }

    virtual bool event(QEvent *event) {
        bool handled = QOpenGLWidget::event(event);
        this->update();
        return handled;
    }

private:

    osgGA::EventQueue *getEventQueue() const {
        osgGA::EventQueue *eventQueue = _mGraphicsWindow->getEventQueue();
        return eventQueue;
    }

    osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> _mGraphicsWindow;
    osg::ref_ptr<osgViewer::Viewer> _mViewer;
    qreal m_scale;
};

int main(int argc, char **argv) {
#if QT_VERSION >= QT_VERSION_CHECK(5,6,0)
    QApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
#else
    qputenv("QT_DEVICE_PIXEL_RATIO", QByteArray("1"));
#endif

    QApplication qapp(argc, argv);
    QMainWindow window;
    QtOSGWidget *widget = new QtOSGWidget(&window);
    window.setCentralWidget(widget);
    window.show();

    return qapp.exec();
}

效果

在这里插入图片描述

方法二:继承 QOpenGLWidget 和 osgViewer::Viewer


链接直达

Qt中嵌入OSG控件的方法

源码(分三部分,OsgContainer.h,OsgContainer.cpp,main.cpp)

1. OsgContainer.h

#ifndef OSGCONTAINER_H
#define OSGCONTAINER_H

#include <QOpenGLWidget>
#include <osgViewer/Viewer>

class QInputEvent;

class OsgContainer : public QOpenGLWidget, public osgViewer::Viewer {
    Q_OBJECT

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

    bool event(QEvent *event);

    void setKeyboardModifiers(QInputEvent *event);
    void keyPressEvent(QKeyEvent *event);
    void keyReleaseEvent(QKeyEvent *event);
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void mouseDoubleClickEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void wheelEvent(QWheelEvent *event);
    void resizeEvent(QResizeEvent *event);
    void moveEvent(QMoveEvent *event);
    void timerEvent(QTimerEvent *);

    osgViewer::Viewer *getOSGViewer() {
        return this;
    }
    osg::Group *getRoot() {
        return root;
    }

protected:
    virtual void paintGL();

private:
    void init3D();
    osg::ref_ptr<osg::Camera> createCamera(int x, int y, int w, int h);

private:
    osg::ref_ptr<osg::Group> root;
    osgViewer::GraphicsWindow *window;
};
#endif // OSGCONTAINER_H

2. OsgContainer.cpp

#include "OsgContainer.h"
#include <QInputEvent>
#include <osg/MatrixTransform>
#include <osgDB/ReadFile>
#include <osgGA/MultiTouchTrackballManipulator>
#include <osgGA/StateSetManipulator>
#include <osgViewer/ViewerEventHandlers>
#include <QApplication>

OsgContainer::OsgContainer(QWidget *parent)
    : QOpenGLWidget(parent) {
    init3D();
    setMouseTracking(true);
    setFocusPolicy(Qt::StrongFocus);
}

OsgContainer::~OsgContainer() {

}

bool OsgContainer::event(QEvent *event) {
    switch (event->type()) {
    case QEvent::TouchBegin:
    case QEvent::TouchEnd:
    case QEvent::TouchUpdate: {
        QList<QTouchEvent::TouchPoint> touchPoints = static_cast<QTouchEvent *>(event)->touchPoints();
        unsigned int id = 0;
        unsigned int tapCount = touchPoints.size();

        osg::ref_ptr<osgGA::GUIEventAdapter> osgEvent(NULL);
        osgGA::GUIEventAdapter::TouchPhase phase = osgGA::GUIEventAdapter::TOUCH_UNKNOWN;
        foreach(const QTouchEvent::TouchPoint &touchPoint, touchPoints) {
            if (!osgEvent) {
                if (event->type() == QEvent::TouchBegin) {
                    phase = osgGA::GUIEventAdapter::TOUCH_BEGAN;
                    osgEvent = window->getEventQueue()->touchBegan(id, osgGA::GUIEventAdapter::TOUCH_BEGAN, touchPoint.pos().x(), touchPoint.pos().y());
                } else if (event->type() == QEvent::TouchEnd) {
                    phase = osgGA::GUIEventAdapter::TOUCH_ENDED;
                    osgEvent = window->getEventQueue()->touchEnded(id, osgGA::GUIEventAdapter::TOUCH_ENDED, touchPoint.pos().x(), touchPoint.pos().y(), tapCount);
                } else if (event->type() == QEvent::TouchUpdate) {
                    phase = osgGA::GUIEventAdapter::TOUCH_MOVED;
                    osgEvent = window->getEventQueue()->touchMoved(id, osgGA::GUIEventAdapter::TOUCH_MOVED, touchPoint.pos().x(), touchPoint.pos().y());
                }
            } else {
                osgEvent->addTouchPoint(id, osgGA::GUIEventAdapter::TOUCH_ENDED, touchPoint.pos().x(), touchPoint.pos().y());
                osgEvent->addTouchPoint(id, phase, touchPoint.pos().x(), touchPoint.pos().y());
            }
            id++;
        }
        break;
    }
    default:
        break;
    }
    return QOpenGLWidget::event(event);
}

void OsgContainer::setKeyboardModifiers(QInputEvent *event) {
    int modkey = event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier);
    unsigned int mask = 0;
    if (modkey & Qt::ShiftModifier) {
        mask |= osgGA::GUIEventAdapter::MODKEY_SHIFT;
    }
    if (modkey & Qt::ControlModifier) {
        mask |= osgGA::GUIEventAdapter::MODKEY_CTRL;
    }
    if (modkey & Qt::AltModifier) {
        mask |= osgGA::GUIEventAdapter::MODKEY_ALT;
    }

    window->getEventQueue()->getCurrentEventState()->setModKeyMask(mask);
    update();
}

void OsgContainer::keyPressEvent(QKeyEvent *event) {
    setKeyboardModifiers(event);
    window->getEventQueue()->keyPress(event->key());
    QOpenGLWidget::keyPressEvent(event);
    update();
}

void OsgContainer::keyReleaseEvent(QKeyEvent *event) {
    setKeyboardModifiers(event);
    window->getEventQueue()->keyRelease(event->key());
    QOpenGLWidget::keyReleaseEvent(event);
    update();
}

void OsgContainer::mousePressEvent(QMouseEvent *event) {
    int button = 0;
    switch (event->button()) {
    case Qt::LeftButton: button = 1; break;
    case Qt::MidButton: button = 2; break;
    case Qt::RightButton: button = 3; break;
    case Qt::NoButton: button = 0; break;
    default: button = 0; break;
    }
    setKeyboardModifiers(event);
    window->getEventQueue()->mouseButtonPress(event->x(), event->y(), button);
    update();
}

void OsgContainer::mouseReleaseEvent(QMouseEvent *event) {
    int button = 0;
    switch (event->button()) {
    case Qt::LeftButton: button = 1; break;
    case Qt::MidButton: button = 2; break;
    case Qt::RightButton: button = 3; break;
    case Qt::NoButton: button = 0; break;
    default: button = 0; break;
    }
    setKeyboardModifiers(event);
    window->getEventQueue()->mouseButtonRelease(event->x(), event->y(), button);

    QOpenGLWidget::mouseReleaseEvent(event);
    update();
}

void OsgContainer::mouseDoubleClickEvent(QMouseEvent *event) {
    int button = 0;
    switch (event->button()) {
    case Qt::LeftButton: button = 1; break;
    case Qt::MidButton: button = 2; break;
    case Qt::RightButton: button = 3; break;
    case Qt::NoButton: button = 0; break;
    default: button = 0; break;
    }
    setKeyboardModifiers(event);
    window->getEventQueue()->mouseDoubleButtonPress(event->x(), event->y(), button);

    QOpenGLWidget::mouseDoubleClickEvent(event);
    update();
}

void OsgContainer::mouseMoveEvent(QMouseEvent *event) {
    setKeyboardModifiers(event);
    window->getEventQueue()->mouseMotion(event->x(), event->y());
    QOpenGLWidget::mouseMoveEvent(event);
    update();
}

void OsgContainer::wheelEvent(QWheelEvent *event) {
    setKeyboardModifiers(event);
    window->getEventQueue()->mouseScroll(
        event->orientation() == Qt::Vertical ?
        (event->delta() > 0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN) :
        (event->delta() > 0 ? osgGA::GUIEventAdapter::SCROLL_LEFT : osgGA::GUIEventAdapter::SCROLL_RIGHT));
    QOpenGLWidget::wheelEvent(event);
    update();
}

void OsgContainer::resizeEvent(QResizeEvent *event) {
    const QSize &size = event->size();
    window->resized(x(), y(), size.width(), size.height());
    window->getEventQueue()->windowResize(x(), y(), size.width(), size.height());
    window->requestRedraw();

    //    const QSize& oldSize = event->oldSize();
    //    int oldWidth = oldSize.width();
    //    int oldHeight = oldSize.height();

    //    int newWidth = size.width();
    //    int newHeight = size.height();

    //    double widthChangeRatio = double(newWidth) / double(oldWidth);
    //    double heigtChangeRatio = double(newHeight) / double(oldHeight);
    //    double aspectRatioChange = widthChangeRatio / heigtChangeRatio;
    QOpenGLWidget::resizeEvent(event);
}

void OsgContainer::moveEvent(QMoveEvent *event) {
    const QPoint &pos = event->pos();
    window->resized(pos.x(), pos.y(), width(), height());
    window->getEventQueue()->windowResize(pos.x(), pos.y(), width(), height());

    QOpenGLWidget::moveEvent(event);
}

void OsgContainer::timerEvent(QTimerEvent *) {
    update();
}

void OsgContainer::paintGL() {
    if (isVisibleTo(QApplication::activeWindow())) {
        frame();
    }
}

void OsgContainer::init3D() {
    root = new osg::Group;
    root->setName("Root");

    setCamera(createCamera(0, 0, width(), height()));
    osg::ref_ptr<osgGA::TrackballManipulator> manipulator = new osgGA::TrackballManipulator;
    setCameraManipulator(manipulator);
    addEventHandler(new osgViewer::StatsHandler);
    addEventHandler(new osgViewer::ThreadingHandler());
    addEventHandler(new osgViewer::HelpHandler);
    addEventHandler(new osgGA::StateSetManipulator(this->getCamera()->getOrCreateStateSet()));
    setThreadingModel(osgViewer::Viewer::SingleThreaded);

    root->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON);
    root->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
    setSceneData(root);

    //    setRunFrameScheme(ON_DEMAND);

    startTimer(10);
}

osg::ref_ptr<osg::Camera> OsgContainer::createCamera(int x, int y, int w, int h) {
    window = new osgViewer::GraphicsWindowEmbedded(x, y, w, h);
    //    osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
    traits->windowDecoration = true;
    traits->x = x;
    traits->y = y;
    traits->width = w;
    traits->height = h;
    traits->doubleBuffer = true;
    traits->sharedContext = 0;

    osg::ref_ptr<osg::Camera> camera = new osg::Camera;
    camera->setGraphicsContext(window);
    camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));
    camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    camera->setProjectionMatrixAsPerspective(
        30.0f, double(traits->width) / double(traits->height), 1.0f, 10000.0f);
    camera->setClearColor(osg::Vec4(0.3, 0.3, 0.6, 0.1));

    return camera.release();
}

3. main.cpp

#include "QtOSG3.h"
#include <QtWidgets/QApplication>
#include <QMainWindow>

#include "OsgContainer.h"

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    QMainWindow window;
    OsgContainer *osgViewer = new OsgContainer(&window);  //(记得提前声明哦)
    window.setCentralWidget(osgViewer);
    window.show();
    return a.exec();
}

效果

在这里插入图片描述

其它实现


以下实现方法或多或少有些问题

  1. Qt中嵌入OSG,结论:编译通过并且可以运行,但是窗口会一闪而过,且不好控制
  2. OSG 与QT 结合,结论:编译不过,错误 14 error LNK2001: 无法解析的外部符号 “public: virtual void __cdecl QGLWidget::updateOverlayGL(void)” (?updateOverlayGL@QGLWidget@@UEAAXXZ) F:\Project_CPlus\QtOSG2\QtOSG2\main.obj QtOSG2
  3. 将OSG嵌入QT窗口系统中,实现拖拽界面,结论:编译不过,提示缺少 OsgLib.h,我也不知道这个文件是自带的还是自己写的…
  4. osg与Qt结合编程,结论:编译不过
  5. 其它…

更灵活的嵌套使用


为了能够更加灵活方便的使用嵌套窗口,我们可以在 QtCreator 中拖拽 QOpenGLWidget ,然后将其提升为自己定义的 OSGWidget

eg
在这里插入图片描述
友情参考链接:Qt自定义控件以及控件的提升

要将OSG模型嵌入Qt窗口,可以使用Qt的OpenGL模块和OSGQt插件。具体步骤如下: 1. 创建一个Qt窗口,继承自QOpenGLWidget。 2. 在窗口的初始化函数,创建一个OSG Viewer对象,并将其设置为OpenGL上下文。 3. 在窗口的paintGL()函数,调用OSG的渲染函数进行渲染。 4. 在窗口的resizeGL()函数,更新OSG Viewer的视口大小。 5. 在Qt的主函数,加载OSGQt插件,以便在Qt应用程序使用OSG。 下面是一个简单的示例代码: ```cpp #include <osgViewer/Viewer> #include <osgQt/GraphicsWindowQt> class OSGWidget : public QOpenGLWidget { public: OSGWidget(QWidget* parent = nullptr) : QOpenGLWidget(parent) { osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits(); traits->windowName = "OSG Widget"; traits->x = x(); traits->y = y(); traits->width = width(); traits->height = height(); traits->windowDecoration = false; traits->doubleBuffer = true; traits->sharedContext = 0; osgQt::GraphicsWindowQt* gw = new osgQt::GraphicsWindowQt(traits.get()); osg::Camera* camera = new osg::Camera; camera->setGraphicsContext(gw); camera->setViewport(new osg::Viewport(0, 0, width(), height())); setCameraManipulator(new osgGA::TrackballManipulator); viewer.setCamera(camera); viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded); } protected: void paintGL() override { viewer.frame(); } void resizeGL(int w, int h) override { viewer.getCamera()->setViewport(new osg::Viewport(0, 0, w, h)); } private: osgViewer::Viewer viewer; }; int main(int argc, char** argv) { QApplication app(argc, argv); osgDB::Registry::instance()->loadLibrary("osgdb_qt.so"); OSGWidget widget; widget.resize(640, 480); widget.show(); return app.exec(); } ``` 这里假设OSG已经正确安装,并且Qt应用程序已经配置好了OpenGL环境。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值