QQuickRenderControl、または他の誰かのOpenGLコンテキストとQMLを友達にする方法。 パートI

私の意見では、Qt 5.4の最近のリリースは 、とりわけ、開発者に非常に好奇心tool盛なツールを提供します。 つまり、Qt開発者はQQuickRenderControlをパブリックAPIの一部にしています。 このクラスの魅力は、OpenGLが使用するコンテキストへのポインターを取得(または設定)する機能を提供する場合、Qmlを他のフレームワークと組み合わせて使用​​できるようになったことです。

一方、私のプロジェクトの1つに取り組んでいる間、親ウィンドウにアクセスするわずかな機会なしに、 CALayer(Mac OS X)でQMLシーンを描画する必要に直面しました。 問題の可能な解決策の1週間の検索は、前述のタスクの発生と同時にリリースステータスを受け取った一致が成功したため、Qt 5.4のQQuickRenderControlを使用することが最も適切な解決策であることを示しました。

最初は、タスクは些細で、数晩で解決されると想定していましたが、どれだけ間違えていましたか?



いくつかのポイント







元の問題を解決するには何をする必要がありますか?



1)FBOでレンダリングし、QQuickRenderControlを介してこのプロセスを制御するためのQQuickWindow設定を実装します。

2)Qmlの読み込みを実装し、結果をQQuickWindowに添付します。

3)マウスおよびキーボードイベントの転送を実装します。

4)FBOを描画します(すべてに対応していました)。



この記事では、パラグラフ1)、後続のパートの残りのパラグラフのみに専念できるようにします(これがおもしろければ)。



QQuickWindowをカスタマイズする



外部QOpenGLContext


開始点は、FBOが最終的に描画されるOpenGLコンテキストです。 しかし、高い確率で、最初はQtとは関係のないコンテキストで作業する必要があるため、コンテキストをオペレーティングシステムの形式からQOpenGLContextのインスタンスに変換する必要があります。 これを行うには、 QOpenGLContext :: setNativeHandleメソッドを使用します。

NSOpenGLContextベースの使用例:



NSOpenGLContext* nativeContext = [super openGLContextForPixelFormat: pixelFormat]; QOpenGLContext* extContext = new QOpenGLContext; extContext->setNativeHandle( QVariant::fromValue( QCocoaNativeContext( nativeContext ) ) ); extContext->create();
      
      





使用可能なネイティブコンテキストのリストは、Qtヘッダーファイル(\ QtPlatformHeadersを含む)で直接表示するのが最適です。 このパートのドキュメントは完全ではありません。



さらに、このコンテキストを使用できます(ただし同時に、このコンテキストの状態の変更が所有者の操作と競合しないように注意深く監視する必要があります)が、共有コンテキストを作成できます。



  QSurfaceFormat format; format.setDepthBufferSize( 16 ); format.setStencilBufferSize( 8 ); context = new QOpenGLContext; context->setFormat( format ); context->setShareContext( extContext ); context->create();
      
      







QMLでOpenGLコンテキストを使用するための重要なニュアンスは、構成された深度バッファーとステンシルバッファーの存在です。そのため、元のコンテキストのパラメーターに影響を与えることができない場合は、「深度バッファーサイズ」と「ステンシルバッファーサイズ」が設定された共有コンテキストを使用する必要があります。



QQuickWindowの作成


QQuickWindowを作成するとき、QQuickRenderControlが最初に作成され、コンストラクターに渡されます。

  QQuickRenderControl* renderControl = new QQuickRenderControl(); QQuickWindow* quickWindow = new QQuickWindow( renderControl ); quickWindow->setGeometry( 0, 0, 640, 480 );
      
      





さらに、FBOの作成をさらに成功させるには、ウィンドウサイズを設定することが重要です。



QQuickRenderControlおよびQOpenGLFramebufferObjectの初期化


QQuickRenderControl :: initializeを呼び出す前に、コンテキストを最新にすることが重要です。 呼び出し中に、sceneGraphInitialized信号が生成されます。これは、FBOを作成するのに適したポイントです(そのため、現在のコンテキストを公開する必要があります)。

  QOpenGLFramebufferObject* fbo = nullptr; connect( quickWindow, &QQuickWindow::sceneGraphInitialized, [&] () { fbo = new QOpenGLFramebufferObject( quickWindow->size(), QOpenGLFramebufferObject::CombinedDepthStencil ); quickWindow->setRenderTarget( fbo ); } ); offscreenSurface = new QOffscreenSurface(); offscreenSurface->setFormat( context->format() ); offscreenSurface->create(); context->makeCurrent( offscreenSurface ); renderControl->initialize( context ); context->doneCurrent();
      
      







レンダリング


レンダリングは、信号QQuickRenderControl :: renderRequestedおよびQQuickRenderControl :: sceneChangedへの反応として行う必要があります。 これら2つのケースの違いは、2番目のケースでは、QQuickRenderControl :: polishItemsおよびQQuickRenderControl :: syncを追加で呼び出す必要があることです。 2番目の重要な機能は、上記のシグナルのハンドラーで直接レンダリングしないことを強くお勧めします。 したがって、間隔が短いタイマーが使用されます。 さて、最後の微妙な点は、共有OpenGLコンテキストを使用する場合、レンダリング後にglFlushを呼び出す必要があることです。それ以外の場合、プライマリコンテキストはFBOの変更を認識しません。



  bool* needSyncAndPolish = new bool; *needSyncAndPolish = true; QTimer* renderTimer = new QTimer; renderTimer->setSingleShot( true ); renderTimer->setInterval( 5 ); connect( renderTimer, &QTimer::timeout, [&] () { if( context->makeCurrent( offscreenSurface ) ) { if( *needPolishAndSync ) { *needPolishAndSync = false; renderControl->polishItems(); renderControl->sync(); } renderControl->render(); quickWindow->resetOpenGLState(); context->functions()->glFlush(); context->doneCurrent(); } ); connect( renderControl, &QQuickRenderControl::renderRequested, [&] () { if( !renderTimer->isActive() ) renderTimer->start(); } ); connect( renderControl, &QQuickRenderControl::sceneChanged, [&] () { *needPolishAndSync = true; if( !renderTimer->isActive() ) renderTimer->start(); } );
      
      







まあ、それは基本的にそれです、タスクの最初の部分は完了しました。



上記の概念を実装するクラスは、GitHubで入手できます: FboQuickWindow.hFboQuickWindow.cpp

コメント、コメント、コメント内の健全な批判を歓迎します。



続き: パートII:QMLのダウンロードパートIII:ユーザー入力の処理



All Articles