В настоящее время мы столкнулись со следующей проблемой: у нас есть приложение, которому необходимо отображать множество отдельных сцен OpenSceneGraph в разных виджетах Qt. Например, у нас может быть один виджет Qt, изображающий сферу, а другой — икосаэдр. Поскольку мы используем OpenSceneGraph 3.0.1, мы следовали пример osgViewerQt из официальной документации для реализации этого.
В примере кода используется QTimer
для принудительного обновления виджета средства просмотра:
connect( &_timer, SIGNAL(timeout()), this, SLOT(update()) );
_timer.start( 10 );
Теперь проблемы начинаются, когда мы хотим создать и отобразить несколько виджетов. Поскольку у каждого виджета есть собственный таймер, производительность быстро снижается с увеличением количества открытых виджетов. Взаимодействие с виджетами OSG не только очень медленное, но и взаимодействие с другими виджетами Qt заметно отстает. Даже недавняя четырехъядерная система почти перегружена, когда открыто примерно 5 окон. Эта проблема определенно не связана с нашим графическим оборудованием. Другие приложения могут отображать гораздо большие сцены (Blender, Meshlab и т. д.) без какого-либо негативного влияния на производительность.
Итак, подведем итог: как лучше всего создать несколько виджетов Qt, показывающих разные сцены OpenSceneGraph без влияния на производительность?
Что мы уже пробовали:
- Мы уже рассматривали возможность использования одного
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;
};
Однако это также привело к значительному снижению производительности. Каждый поток по-прежнему требует много процессорного времени (что неудивительно, поскольку основное взаимодействие по-прежнему обрабатывается таймером). Единственное преимущество этого подхода заключается в том, что по крайней мере остается возможным взаимодействие с другими виджетами Qt.
Идеальным решением для нас был бы виджет, который запускает запросы на перерисовку только тогда, когда пользователь взаимодействует с ним, например, щелкнув, двойной щелчок, прокрутив. em> и т. д. Точнее, этот виджет должен оставаться бездействующим до тех пор, пока не возникнет необходимость в обновлении. Возможно ли что-то подобное этому вообще? Будем рады любым предложениям.