2

現在、次の問題に直面しています。さまざまな Qt ウィジェットで多数の個別の OpenSceneGraph シーンを表示する必要があるアプリケーションがあります。たとえば、1 つの Qt ウィジェットが球体を表し、別のウィジェットが 20 面体を表す場合があります。OpenSceneGraph 3.0.1 を使用しているため、これを実装するために公式ドキュメントの osgViewerQt の例に従いました。

サンプル コードではQTimer、ビューア ウィジェットの更新を強制するために を使用しています。

    connect( &_timer, SIGNAL(timeout()), this, SLOT(update()) );
    _timer.start( 10 );

問題は、複数のウィジェットを作成して表示したいときに始まります。各ウィジェットには独自のタイマーが付属しているため、開いているウィジェットの数に応じてパフォーマンスが急速に低下します。OSG ウィジェットとの対話が非常に遅いだけでなく、他のQt ウィジェットとの対話も著しく遅くなります。最近の中途半端なクアッドコア システムでさえ、約 5 つのウィンドウが開いているとほとんど圧倒されます。この問題は、グラフィック ハードウェアとはまったく関係ありません。他のアプリケーション (Blender、Meshlab など) は、パフォーマンスに悪影響を与えることなく、より大きなシーンをレンダリングできます。

要約すると、パフォーマンスに影響を与えることなく、異なる OpenSceneGraph シーンを表示する複数の Qt ウィジェットを作成する最良の方法は何でしょうか?

すでに試したこと:

  • すべてのシーン オブジェクトosgViewer::CompositeViewerのレンダリングに 1 つの を使用することは既に検討しました。ただし、単一のウィジェットとのやり取りが非常に複雑になる可能性があるため、このアイデアは今のところ破棄しました。
  • osgQtWidgets の例で詳しく説明されているように、それぞれのレンダリング部分をosgViewer::CompositeViewer別のスレッドに入れてみました。

2 回目の試行 (スレッドを使用) は、おおよそ次のようになります。

   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 ウィジェットとの対話が可能であることです。

私たちにとって理想的な解決策は、ユーザーがクリックダブルクリックスクロールなどの操作を行うたびに再描画リクエストのみを起動するウィジェットです。より正確には、このウィジェットは更新が必要になるまでアイドル状態のままにする必要があります。これに似たことがまったく可能ですか?ご提案をお待ちしております。

4

4 に答える 4

1

この問題に対していくつかのモデルを試した結果、完全に機能するモデルを見つけたことを報告できてうれしく思います。基本的にオブジェクトをラップし、単に を呼び出すQThread(上記のスレッドに似た) を使用しています。osgViewer::ViewerBaseviewer->run()

CPU 使用率を低く抑える秘訣は、OpenSceneGraph にオンデマンドのみのレンダリングを強制することです。さまざまなオプションを試した結果、次の 2 つの設定が最適であることがわかりました。

viewer->setRunFrameScheme( osgViewer::ViewerBase::ON_DEMAND );
viewer->setThreadingModel( osgViewer::ViewerBase::CullDrawThreadPerContext );

このように変更されたビューアは、カリングと描画に複数のスレッドを使用しながら、継続的な更新に誤った CPU サイクルを使用しません。もちろん、場合によっては他のスレッド モデルの方が優れたパフォーマンスを発揮することもありますが、私にとってはこれで十分でした。

他の誰かが同様の解決策を試みる場合は、一部の操作で明示的な再描画要求が必要になることに注意してください。たとえば、OSG オブジェクトとの対話を処理する場合や、独自のクラスを作成する場合、ビューアの設定を変更した後CameraManipulatorに呼び出しても問題はありません。viewer->requestRedraw()それ以外の場合、ビューアは、ウィジェットの再描画が必要な場合にのみ更新されます。

要するに、これが私が学んだことです:

  • レンダリングにタイマーを使用しない
  • まだ複数のスレッドをあきらめないでください
  • ソースコードを読むことに勝るものはありません (公式の OSG の例では詳細が不足している場合がありましたが、ソースは決して嘘をつきません...)
于 2012-09-04T08:15:38.700 に答える
0

それは可能であるはずです。彼らがウィジェットを更新するために100Hzで動作するタイマーを使用したとは信じられません-それは本当にそれを行う正しい方法ではありません。

OSGのアーキテクチャについてはわかりませんが、データが変更されたときにOSGからコールバックを取得する方法を理解する必要があります。コールバックでは、次のように更新イベントを適切なウィジェットにキューイングするだけです。

void OSGCallbackForWidgetA()
{
  QCoreApplication::postEvent(widgetA, new QEvent(QEvent::UpdateRequest),
                              Qt::LowEventPriority);
}

このコールバックコードはスレッドセーフであり、QThreadによって開始されたかどうかに関係なく、任意のスレッドで呼び出すことができます。イベントは圧縮されます。つまり、フラグのように機能します。投稿するとフラグが設定され、ウィジェットが更新を終了するとフラグがリセットされます。更新が保留中に複数回投稿しても、イベントキューにイベントが追加されることはなく、複数の更新を意味することもありません。

于 2012-06-08T12:41:48.307 に答える
0

また、これを機能させる方法を理解するのにもかなりの時間を費やしました。

Gnosophilon からの回答は Qt5 では機能しないと思います。コンテキスト スレッドを切り替えるための規則が Qt4 よりも厳しいためです (つまり、moveToThread()OpenGL コンテキスト オブジェクトで への呼び出しが必要です)。執筆時点では、OSG はこの規則を満たしていません。(少なくとも、私はそれを機能させることができませんでした)

別のスレッドでそれを行う方法がわかりませんが、固定間隔タイマーを使用せずに UI スレッドでシーンをスムーズにレンダリングするには、次のようにします。

viewer_->setRunFrameScheme(osgViewer::ViewerBase::ON_DEMAND);
viewer_->setThreadingModel(osgViewer::CompositeViewer::SingleThreaded);
osgQt::initQtWindowingSystem();
osgQt::setViewer(viewer_.get());

osgQt::setViewer()グローバル変数で処理するため、一度に使用できるビューアは 1 つだけです。(CompositeViewer当然のことかもしれません)

于 2014-01-20T17:06:39.907 に答える