我们目前面临以下问题:我们有一个应用程序需要在不同的 Qt 小部件中显示大量单独的 OpenSceneGraph 场景。例如,我们可能有一个 Qt 小部件描绘一个球体,而另一个小部件描绘一个二十面体。由于我们使用的是 OpenSceneGraph 3.0.1,因此我们遵循官方文档中的 osgViewerQt 示例来实现这一点。
示例代码使用 aQTimer
来强制更新查看器小部件:
connect( &_timer, SIGNAL(timeout()), this, SLOT(update()) );
_timer.start( 10 );
当我们想要创建和显示多个小部件时,问题就开始了。由于每个小部件都有自己的计时器,因此性能会随着打开小部件的数量而迅速下降。不仅与 OSG 小部件的交互非常缓慢,而且与其他Qt 小部件的交互也明显滞后。当大约 5 个窗口打开时,即使是中途最近的四核系统也几乎不堪重负。这个问题绝对与我们的图形硬件无关。其他应用程序可能会渲染更大的场景(Blender、Meshlab 等),而不会对性能产生任何负面影响。
所以,总结一下:在不影响性能的情况下,创建多个显示不同 OpenSceneGraph 场景的 Qt 小部件的最佳方法是什么?
我们已经尝试过的:
- 我们已经考虑过使用单个
osgViewer::CompositeViewer
来渲染所有场景对象。但是,我们暂时放弃了这个想法,因为它可能会使与单个小部件的交互变得非常复杂。 - 我们尝试将每个的渲染部分
osgViewer::CompositeViewer
放在一个单独的线程中,如osgQtWidgets 示例所详述。
我们的第二次尝试(使用线程)大致如下:
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;
};
然而,这也导致了性能的显着下降。每个线程仍然需要很多 CPU 时间(这并不奇怪,因为基本交互仍然由计时器处理)。这种方法的唯一优点是至少可以与其他Qt 小部件进行交互。
对我们来说理想的解决方案是一个小部件,它只在用户与之交互时触发重绘请求,例如通过单击、双击、滚动等。更准确地说,这个小部件应该保持空闲状态,直到需要更新。有没有可能发生类似的事情?我们欢迎任何建议。