OSG嵌入QT的简明总结
目录
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工程如下:
编译运行后如下:
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的类。所以这里面问题还是不少的,好在内容相对较少,以后有空可以自己改进。
上一篇: 喝醉了还能看到更多奇幻的事