欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

OSG嵌入QT的简明总结

程序员文章站 2022-07-11 16:55:12
[toc] 1.解决方案 不得不说关于OSG的资料实在太零散了,搜索了很多关于OSG在QT下的解决方案,都是各有各的说法,有的说的不是很清楚,有的已经过时了。这里提供一下自己的解决方案吧。 在远古的OSG里面,应该是提供对QT的支持的;不过应该是由于QT版本变动比较大,现在的OSG版本应该已经没有了 ......

目录

1.解决方案

不得不说关于osg的资料实在太零散了,搜索了很多关于osg在qt下的解决方案,都是各有各的说法,有的说的不是很清楚,有的已经过时了。这里提供一下自己的解决方案吧。
在远古的osg里面,应该是提供对qt的支持的;不过应该是由于qt版本变动比较大,现在的osg版本应该已经没有了。但是在github上又有了新的osgqt项目(地址:https://github.com/openscenegraph/osgqt) 用来解决这个问题。
osgqt是个简单的小项目,其实没有必要额外的编译,最核心的是个名为graphicswindowqt的类,只需要复制graphicswindowqt.h和graphicswindowqt.cpp到qt工程里面就可以使用了。同时osgqt给出了一个名为osgviewerqt的样例,也仅仅只是个cpp文件。结合两者,一个简单的示例就出来了。
qt工程如下:
OSG嵌入QT的简明总结
编译运行后如下:
OSG嵌入QT的简明总结

2.存在问题

1) 警告提示

上述项目直接运行,会出现诸如“qopenglcontext::swapbuffers() called with non-exposed window, behavior is undefined”的警告。查阅网上的英文资料,大意说是因为opengl环境未初始化产生的。在osgviewerqt中绑定了一个定时器,每隔10ms就调用frame()来绘制一帧,而这个定时器是在构造函数的时候就开始调用了,没有等待qt中opengl环境的生成。在这里我把定时器的部分给改进了一下,等待osg的环境初始化完成在启动定时器,这个警告就没有了。osgviewerqt改进后的代码如下:

#include <qtimer>
#include <qapplication>
#include <qgridlayout>

#include <osgviewer/compositeviewer>
#include <osgviewer/viewereventhandlers>

#include <osgga/multitouchtrackballmanipulator>

#include <osgdb/readfile>

#include "graphicswindowqt"

#include <iostream>

class viewerwidget : public qwidget, public osgviewer::compositeviewer
{
public:
    viewerwidget(qwidget* parent = 0, qt::windowflags f = 0, osgviewer::viewerbase::threadingmodel threadingmodel=osgviewer::compositeviewer::singlethreaded) : qwidget(parent, f)
    {
        setthreadingmodel(threadingmodel);

        // disable the default setting of viewer.done() by pressing escape.
        setkeyeventsetsdone(0);

        qwidget* widget1 = addviewwidget( creategraphicswindow(0,0,100,100), osgdb::readrefnodefile("d:/work/osgbuild/openscenegraph-data/cow.osgt") );
        qwidget* widget2 = addviewwidget( creategraphicswindow(0,0,100,100), osgdb::readrefnodefile("d:/work/osgbuild/openscenegraph-data/glider.osgt") );
        qwidget* widget3 = addviewwidget( creategraphicswindow(0,0,100,100), osgdb::readrefnodefile("d:/work/osgbuild/openscenegraph-data/axes.osgt") );
        qwidget* widget4 = addviewwidget( creategraphicswindow(0,0,100,100), osgdb::readrefnodefile("d:/work/osgbuild/openscenegraph-data/fountain.osgt") );
//        qwidget* popupwidget = addviewwidget( creategraphicswindow(900,100,320,240,"popup window",true), osgdb::readrefnodefile("d:/work/osgbuild/openscenegraph-data/dumptruck.osgt") );
//        popupwidget->show();

        qgridlayout* grid = new qgridlayout;
        grid->addwidget( widget1, 0, 0 );
        grid->addwidget( widget2, 0, 1 );
        grid->addwidget( widget3, 1, 0 );
        grid->addwidget( widget4, 1, 1 );
        setlayout( grid );

        //connect( &_timer, signal(timeout()), this, slot(update()) );
        //_timer.start( 10 );
    }

    qwidget* addviewwidget( osgqt::graphicswindowqt* gw, osg::ref_ptr<osg::node> scene )
    {
        osgviewer::view* view = new osgviewer::view;
        addview( view );

        osg::camera* camera = view->getcamera();
        camera->setgraphicscontext( gw );

        const osg::graphicscontext::traits* traits = gw->gettraits();

        camera->setclearcolor( osg::vec4(0.2, 0.2, 0.6, 1.0) );
        camera->setviewport( new osg::viewport(0, 0, traits->width, traits->height) );

        // set the draw and read buffers up for a double buffered window with rendering going to back buffer
        camera->setdrawbuffer(gl_back);
        camera->setreadbuffer(gl_back);

        camera->setprojectionmatrixasperspective(30.0f, static_cast<double>(traits->width)/static_cast<double>(traits->height), 1.0f, 10000.0f );

        view->setscenedata( scene );
        view->addeventhandler( new osgviewer::statshandler );
        view->setcameramanipulator( new osgga::multitouchtrackballmanipulator );
        gw->settoucheventsenabled( true );
        return gw->getglwidget();
    }

    osgqt::graphicswindowqt* creategraphicswindow( int x, int y, int w, int h, const std::string& name="", bool windowdecoration=false )
    {
        osg::displaysettings* ds = osg::displaysettings::instance().get();
        osg::ref_ptr<osg::graphicscontext::traits> traits = new osg::graphicscontext::traits;
        traits->windowname = name;
        traits->windowdecoration = windowdecoration;
        traits->x = x;
        traits->y = y;
        traits->width = w;
        traits->height = h;
        traits->doublebuffer = true;
        traits->alpha = ds->getminimumnumalphabits();
        traits->stencil = ds->getminimumnumstencilbits();
        traits->samplebuffers = ds->getmultisamples();
        traits->samples = ds->getnummultisamples();

        return new osgqt::graphicswindowqt(traits.get());
    }

//    virtual void paintevent( qpaintevent* /*event*/ )
//    { frame(); }

    //定时器事件
    void timerevent(qtimerevent* )
    {
        frame();
    }

    //启动定时器绘制
    void show()
    {
        qwidget::show();
        _timerid = starttimer(10);
    }


protected:

    //qtimer _timer;
    int _timerid;               //定时器id
};

int main( int argc, char** argv )
{
    osg::argumentparser arguments(&argc, argv);

#if qt_version >= 0x050000
    // qt5 is currently crashing and reporting "cannot make qopenglcontext current in a different thread" when the viewer is run multi-threaded, this is regression from qt4
    osgviewer::viewerbase::threadingmodel threadingmodel = osgviewer::viewerbase::singlethreaded;
#else
    osgviewer::viewerbase::threadingmodel threadingmodel = osgviewer::viewerbase::culldrawthreadpercontext;
#endif

    while (arguments.read("--singlethreaded")) threadingmodel = osgviewer::viewerbase::singlethreaded;
    while (arguments.read("--culldrawthreadpercontext")) threadingmodel = osgviewer::viewerbase::culldrawthreadpercontext;
    while (arguments.read("--drawthreadpercontext")) threadingmodel = osgviewer::viewerbase::drawthreadpercontext;
    while (arguments.read("--cullthreadpercameradrawthreadpercontext")) threadingmodel = osgviewer::viewerbase::cullthreadpercameradrawthreadpercontext;

#if qt_version >= 0x040800
    // required for multithreaded qglwidget on linux/x11, see http://blog.qt.io/blog/2011/06/03/threaded-opengl-in-4-8/
    if (threadingmodel != osgviewer::viewerbase::singlethreaded)
        qapplication::setattribute(qt::aa_x11initthreads);
#endif

    qapplication app(argc, argv);
    viewerwidget* viewwidget = new viewerwidget(0, qt::widget, threadingmodel);
    viewwidget->setgeometry( 100, 100, 800, 600 );
    viewwidget->show();
    return app.exec();
}

2) 多线程问题

在osg中提供了诸如culldrawthreadpercontext等多线程模式,但是在这里是没办法支持这些多线程模式的,只能支持单线程。在网上查阅了一些解决方案,但是最后都不是很完美,有空再把其解决方案写出来。

3) 其他

graphicswindowqt最终继承的还是qt中的qglwidget类,提供opengl功能。而在新版本的qt中,这个类已经被废弃了,取而代之的是一个叫做qopenglwidget的类。所以这里面问题还是不少的,好在内容相对较少,以后有空可以自己改进。