7

私はこの問題に取り組み、もっとうまくやれることを知っていました。

問題:

QGLWidget (Qt OpenGL contextview) を Qt ウィジェットでオーバーレイすると、Qt は Qt フレームごとにこれらのウィジェットを再描画します。

Qt は、60 fps 以上で常にウィンドウ全体を再描画するように構築されていないため、非常に遅くなります。

私の考え:

Qt に別のものを使用して描画させます: 透明なテクスチャです。再描画するたびに OpenGL でこのテクスチャを使用し、他のすべての上に描画します。Qt が OpenGL コンテキスト ビューとのすべてのやり取りを、テクスチャに描画されたウィジェットにリダイレクトするようにします。

利点は、Qt が必要なときに再描画するだけでよく (たとえば、ウィジェットをホバーまたはクリックしたり、テキスト フィールド内のテキスト カーソルを点滅させたり)、部分的な再描画をより高速に実行できることです。

私の質問:

これにアプローチする方法は?テクスチャに描画するように Qt に指示するにはどうすればよいですか? ウィジェットとのやり取りを別のウィジェットにリダイレクトするにはどうすればよいですか (たとえば、コンテキスト ビューでテクスチャ描画ウィジェット内のチェックボックスがある領域の上にマウスを移動すると、Qt はこのイベントをチェックボックスに登録し、反映するように再描画する必要があります)。かぶせた状態)

4

1 に答える 1

5

私の場合、2Dレンダリングはウィジェットではありませんが、CADのようなアプリでは、2Dレンダリングと3Dレンダリングを分けていますが、違いはありません。これが問題へのアプローチ方法です。

  1. ウィジェットを変更すると、ウィジェットがにレンダリングされます。QGLFramebufferObjectこれを行うには、FBOをのとして使用し、QPaintDeviceQPainter呼び出しQGLWidget::paintEvent(..)ますmyWidget->render( myQPainter, ...)。ウィジェットの数に関係なく、同じFBOに対してのみこれを繰り返します。各ウィジェットにFBOを作成しないでください...「通常の」フレームバッファーのように、最初にクリアすることを忘れないでください。
  2. QGLFramebufferObject現在のOpenGLバックグラウンドが変更されたら、同じ方法で、標準のOpenGL呼び出しを使用して別のバックグラウンドにレンダリングします。
  3. パススルー頂点シェーダー(「カメラ」は単なる単位立方体になります)と、2つのテクスチャを互いに重ねることができる非常に単純なフラグメントシェーダーを作成します。
  4. の最後で、QGLWidget::paintEvent(..)シェーダープログラムをアクティブにし、フレームバッファーをテクスチャとしてバインドし(myFBO->texture()ハンドルを取得)、ユニットクワッドをレンダリングします。カメラは単位正方形であり、ビューポートサイズがFBOサイズを定義しているため、ビューポートピクセルが完全に塗りつぶされます。

ただし、それは簡単な部分です...難しい部分はウィジェットの相互作用です。基本的に「プロキシ」をレンダリングしているため、「実際の」ウィジェットを非表示にしたまま、「実際の」ウィジェットと「プロキシ」ウィジェットの間の相互作用を中継する必要があります。開始方法は次のとおりです。

  • 一部のオペレーティングシステムは、ウィジェットを表示せずにレンダリングすることについて少し奇妙です。そのため、インスタンス化後にウィジェットを表示してから非表示にする必要がある場合があります。Qtの巧妙なペイントキューのため、実際に画面に表示される可能性はほとんどありません。
  • ビューポートですべてのマウスイベントをキャッチし、カーソルが置かれている「プロキシ」ウィジェット(存在する場合)を特定し、それをオフセットして「実際の」非表示ウィジェットの相対位置を取得します。この値は、どの親オブジェクトに依存します。 「実際の」ウィジェットには、ある場合はあります。次に、ウィジェットのフレームバッファを再描画する前に、イベントを「実際の」ウィジェットに渡します。

再描画を適切に処理するには、「フラグ付け」システムも作成する必要があったことを述べておく必要があります。多くの同時イベントが発生する可能性があるため(マウスについて考えるだけでなく)、すべてのウィジェットイベントがウィジェットFBOの再描画をトリガーする必要はありませんが、再描画は1回だけにする必要があります。そこで、アプリケーション内の何かがビューポート内の何かを視覚的に変更できる場合、ビューポートに「ダーティ」のフラグを立てるシステムを作成しました。次に、QTimer目標とするfpsの数に関係なく(私の状況ではシーンが非常に重くなる可能性があるため、フレームにかかる時間を計測し、その値+ 10%を次のチェックのタイマー遅延として使用しました。このようにシステムはレンダリングが遅くなったときに攻撃されません)。次に、ダーティステータスを確認します。ダーティの場合は再描画します。それ以外の場合はしないでください。3D用と2D用の2つのダーティフラグを使用すると、作業が楽になることがわかりました。ただし、OpenGL描画で一定の描画速度を維持する必要がある場合は、おそらく2つは必要ありません。

私がやったことはそれを行うのに最も簡単な方法ではなかったと思いますが、それはチューニングとプロファイリングのための十分な範囲を提供します-それは長期的には人生を楽にします。すべての答えは間違いなくこの投稿にはありませんが、うまくいけば、それはあなたを戦略への道に導くでしょう。

于 2012-08-07T16:52:48.757 に答える