We are currently facing the following problem: We have an application that needs to display a multitude of separate OpenSceneGraph scenes in different Qt widgets. For example, we might have one Qt widget depicting a sphere, while another widget depicts an icosahedron. Since we are using OpenSceneGraph 3.0.1, we followed the osgViewerQt example from the official documentation for implementing this.
The example code uses a QTimer
in order to force updates for the viewer widget:
connect( &_timer, SIGNAL(timeout()), this, SLOT(update()) );
_timer.start( 10 );
The problems now begin when we want to create and show multiple widgets. Since each widget comes with its own timer, performance rapidly decreases with the number of open widgets. Not only is the interaction with the OSG widgets very slow, also the interaction with other Qt widgets noticeably lags. Even a halfway recent quad-core system is almost overwhelmed when approximately 5 windows are open. This issue is definitely not related to our graphics hardware. Other applications may render much larger scenes (Blender, Meshlab etc.) without any negative performance impact.
So, to summarize: What would be the best way of creating multiple Qt widgets showing different OpenSceneGraph scenes without a performance impact?
What we already tried:
- We already considered using a single
osgViewer::CompositeViewer
for rendering all scene objects. However, we discarded this idea for now because it will probably make interactions with a single widget very complicated. - We tried putting the rendering portion of each
osgViewer::CompositeViewer
in a separate thread as detailed by the osgQtWidgets example.
Our second try (using threads) looked roughly like this:
class ViewerFrameThread : public OpenThreads::Thread
{
public:
ViewerFrameThread(osgViewer::ViewerBase* viewerBase):
_viewerBase(viewerBase) {}
~ViewerFrameThread()
{
cancel();
while(isRunning())
{
OpenThreads::Thread::YieldCurrentThread();
}
}
int cancel()
{
_viewerBase->setDone(true);
return 0;
}
void run()
{
int result = _viewerBase->run();
}
osg::ref_ptr<osgViewer::ViewerBase> _viewerBase;
};
However, this also resulted in a remarkable performance decrease. Each thread still requires much CPU time (which is not surprising as the basic interaction is still handled with a timer). The only advantage of this approach is that at least interaction with other Qt widgets remain possible.
The ideal solution for us would be a widget that only fires redraw requests whenever the user interacts with it, for example by clicking, double-clicking, scrolling etc. More precisely, this widget should remain idle until there is a need for an update. Is something akin to this possible at all? We would welcome any suggestions.