QOpenGLWidget Class
QOpenGLWidgetクラスは、OpenGLグラフィックスをレンダリングするためのウィジェットです。詳細...
Header: | #include <QOpenGLWidget> |
CMake: | find_package(Qt6 REQUIRED COMPONENTS OpenGLWidgets) target_link_libraries(mytarget PRIVATE Qt6::OpenGLWidgets) |
qmake: | QT += openglwidgets |
Inherits: | QWidget |
パブリック型
(since 6.5) enum | TargetBuffer { LeftBuffer, RightBuffer } |
enum | UpdateBehavior { NoPartialUpdate, PartialUpdate } |
パブリック関数
QOpenGLWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()) | |
virtual | ~QOpenGLWidget() |
QOpenGLContext * | context() const |
(since 6.5) QOpenGLWidget::TargetBuffer | currentTargetBuffer() const |
GLuint | defaultFramebufferObject() const |
(since 6.5) GLuint | defaultFramebufferObject(QOpenGLWidget::TargetBuffer targetBuffer) const |
void | doneCurrent() |
QSurfaceFormat | format() const |
QImage | grabFramebuffer() |
(since 6.5) QImage | grabFramebuffer(QOpenGLWidget::TargetBuffer targetBuffer) |
bool | isValid() const |
void | makeCurrent() |
(since 6.5) void | makeCurrent(QOpenGLWidget::TargetBuffer targetBuffer) |
void | setFormat(const QSurfaceFormat &format) |
void | setTextureFormat(GLenum texFormat) |
void | setUpdateBehavior(QOpenGLWidget::UpdateBehavior updateBehavior) |
GLenum | textureFormat() const |
QOpenGLWidget::UpdateBehavior | updateBehavior() const |
シグナル
void | aboutToCompose() |
void | aboutToResize() |
void | frameSwapped() |
void | resized() |
保護された関数
virtual void | initializeGL() |
virtual void | paintGL() |
virtual void | resizeGL(int w, int h) |
再実装された保護された関数
virtual bool | event(QEvent *e) override |
virtual int | metric(QPaintDevice::PaintDeviceMetric metric) const override |
virtual QPaintEngine * | paintEngine() const override |
virtual void | paintEvent(QPaintEvent *e) override |
virtual QPaintDevice * | redirected(QPoint *p) const override |
virtual void | resizeEvent(QResizeEvent *e) override |
詳しい説明
QOpenGLWidgetは、Qtアプリケーションに統合されたOpenGLグラフィックスを表示する機能を提供します。使い方はとても簡単です:あなたのクラスをこのクラスから継承させ、他のQWidget のようにサブクラスを使用します。ただし、QPainter と標準のOpenGLレンダリングコマンドのどちらかを使用することができます。
QOpenGLWidgetは、典型的なOpenGLタスクを実行するために、サブクラスで再実装できる3つの便利な仮想関数を提供します:
- paintGL() - OpenGLシーンをレンダリングします。ウィジェットを更新する必要があるときはいつでも呼び出されます。
- resizeGL() - OpenGLビューポートや投影などを設定します。ウィジェットのサイズが変更されるたびに呼び出されます(新しく作成されたウィジェットは自動的にリサイズイベントを受け取るので、初めて表示されるときにも呼び出されます)。
- initializeGL() - OpenGLリソースと状態を設定します。resizeGL() またはpaintGL() が最初に呼び出される前に、1 回呼び出されます。
paintGL() 以外の場所から再描画をトリガーする必要がある場合(典型的な例は、timers を使用してシーンをアニメートする場合)、ウィジェットのupdate() 関数を呼び出して更新をスケジュールする必要があります。
ウィジェットの OpenGL レンダリングコンテキストは、paintGL()、resizeGL()、またはinitializeGL() が呼び出されたときに現在の状態になります。他の場所(ウィジェットのコンストラクタや独自のペイント関数など)から標準OpenGL API関数を呼び出す必要がある場合は、最初にmakeCurrent ()を呼び出す必要があります。
すべてのレンダリングはOpenGLフレームバッファオブジェクトに行われます。makeCurrent() は、それがコンテキストにバインドされていることを確認します。paintGL()のレンダリングコードで追加のフレームバッファオブジェクトを作成してバインドするときは、この点に注意してください。決してID 0のフレームバッファを再バインドしないでください。代わりに、defaultFramebufferObject ()を呼び出して、バインドされるべきIDを取得してください。
QOpenGLWidgetは、プラットフォームがサポートしている場合、異なるOpenGLバージョンとプロファイルを使用することができます。setFormat()で要求されたフォーマットを設定するだけです。しかし、同じウィンドウに複数のQOpenGLWidgetインスタンスがある場合、それらのインスタンスがすべて同じフォーマットを使うか、少なくともコンテキストを非シャーラブルにしないフォーマットを使う必要があることに注意してください。この問題を解決するには、setFormat() の代わりにQSurfaceFormat::setDefaultFormat() を使用することをお勧めします。
注意: QApplication インスタンスを構築する前にQSurfaceFormat::setDefaultFormat() を呼び出すことは、OpenGL コアプロファイルコンテキストが要求されたとき、いくつかのプラットフォーム(たとえば macOS)では必須です。これは、すべての内部コンテキストが正しいバージョンとプロファイルを使用して作成されるため、コンテキスト間のリソース共有が機能的に維持されることを保証するためです。
ペイントテクニック
上述したように、QOpenGLWidgetをサブクラス化して、純粋な3Dコンテンツを以下の方法でレンダリングします:
- initializeGL ()とresizeGL ()関数を再実装して、OpenGL状態を設定し、透視変換を提供します。
- paintGL ()を再実装し、OpenGL関数のみを呼び出して3Dシーンを描画する。
また、QPainter を使用して、QOpenGLWidget サブクラスに 2D グラフィックスを描画することもできます:
- paintGL() では、OpenGL コマンドを発行する代わりに、ウィジェットで使用するQPainter オブジェクトを構築します。
- QPainter のメンバ関数を使用してプリミティブを描画します。
- 直接OpenGLコマンドを発行することもできます。ただし、ペインターのbeginNativePainting()とendNativePainting()の呼び出しで囲む必要があります。
QPainter のみを使用して描画を行う場合、通常のウィジェットの場合と同様に、paintEvent() を再実装して描画を行うことも可能です。
- paintEvent() 関数を再実装する。
- ウィジェットをターゲットとするQPainter オブジェクトを構築します。ウィジェットをコンストラクタまたはQPainter::begin() 関数に渡します。
- QPainter のメンバ関数を使用してプリミティブを描画します。
- 描画が終了すると、QPainter インスタンスが破棄されます。または、QPainter::end() を明示的に呼び出します。
OpenGL関数呼び出し、ヘッダー、QOpenGLFunctions
OpenGL関数を呼び出すときは、関数を直接呼び出さないことを強く推奨します。その代わりに、QOpenGLFunctions (ポータブル・アプリケーションを作成する場合)か、バージョン管理されたバリアント(例えば、最新のデスクトップ専用OpenGLをターゲットにする場合は、QOpenGLFunctions_3_2_Core と同様のもの)を使用することを好みます。このようにすることで、アプリケーションはすべてのQtビルド構成で正しく動作します。
paintGL() では、QOpenGLContext::currentContext() を呼び出すことで、現在のコンテキストに常にアクセスできます。このコンテキストから、すでに初期化され、すぐに使用できるQOpenGLFunctions インスタンスは、QOpenGLContext::functions() を呼び出すことで取得可能です。すべてのGL呼び出しの前に接頭辞を付ける代わりに、QOpenGLFunctions を継承し、initializeGL() の中でQOpenGLFunctions::initializeOpenGLFunctions() を呼び出す方法もあります。
OpenGLヘッダに関しては、ほとんどの場合、GL.hのようなヘッダを直接インクルードする必要はないことに注意してください。OpenGL関連のQtヘッダはqopengl.hをインクルードし、そのシステムに適したヘッダをインクルードします。これはOpenGL ES 3.xまたは2.0ヘッダーで、利用可能な最も高いバージョンかもしれませんし、システムが提供するgl.hかもしれません。さらに、拡張ヘッダーのコピー(システムによってはglext.hと呼ばれます)は、OpenGLとOpenGL ESの両方でQtの一部として提供されます。これらは実行可能なプラットフォームでは自動的にインクルードされます。つまり、ARB、EXT、OES拡張からの定数や関数ポインタの型定義は自動的に利用可能になります。
コード例
手始めに、最も単純なQOpenGLWidgetサブクラスは次のようになります:
class MyGLWidget : public QOpenGLWidget { public: MyGLWidget(QWidget *parent) : QOpenGLWidget(parent) { } protected: void initializeGL() override { // Set up the rendering context, load shaders and other resources, etc.: QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); f->glClearColor(1.0f, 1.0f, 1.0f, 1.0f); ... } void resizeGL(int w, int h) override { // Update projection matrix and other size related settings: m_projection.setToIdentity(); m_projection.perspective(45.0f, w / float(h), 0.01f, 100.0f); ... } void paintGL() override { // Draw the scene: QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); f->glClear(GL_COLOR_BUFFER_BIT); ... } };
代わりに、QOpenGLFunctions から派生させることで、OpenGL呼び出しの接頭辞を避けることができます:
class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions { ... void initializeGL() override { initializeOpenGLFunctions(); glClearColor(...); ... } ... };
与えられたOpenGLバージョンやプロファイルと互換性のあるコンテキストを取得したり、深度やステンシルバッファを要求するには、setFormat ()を呼び出します:
QOpenGLWidget *widget = new QOpenGLWidget(parent); QSurfaceFormat format; format.setDepthBufferSize(24); format.setStencilBufferSize(8); format.setVersion(3, 2); format.setProfile(QSurfaceFormat::CoreProfile); widget->setFormat(format); // must be called before the widget or its parent window gets shown
注意: 深度バッファとステンシルバッファが基礎となるウィンドウシステムインタフェースから要求されることを確実にするのはアプリケーション次第です。0でない深度バッファサイズを要求しなければ、深度バッファが利用可能であるという保証はなく、結果として深度テストに関連するOpenGL操作は期待通りに機能しないかもしれない。一般的に使用される深度バッファサイズ要求とステンシルバッファサイズ要求は、それぞれ24と8である。
OpenGL 3.0+のコンテキストでは、移植性が重要でない場合、バージョン化されたQOpenGLFunctions バリアントは、与えられたバージョンで利用可能なすべての最新のOpenGL関数に簡単にアクセスできます:
... void paintGL() override { QOpenGLFunctions_3_2_Core *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>(); ... f->glDrawArraysInstanced(...); ... } ...
上述したように、要求されたフォーマットをグローバルに設定し、アプリケーションの寿命の間、すべてのウィンドウとコンテキストに適用されるようにする方が、よりシンプルで堅牢です。以下はその例です:
int main(int argc, char **argv) { QApplication app(argc, argv); QSurfaceFormat format; format.setDepthBufferSize(24); format.setStencilBufferSize(8); format.setVersion(3, 2); format.setProfile(QSurfaceFormat::CoreProfile); QSurfaceFormat::setDefaultFormat(format); MyWidget widget; widget.show(); return app.exec(); }
マルチサンプリング
マルチサンプリングを有効にするには、setFormat ()に渡されるQSurfaceFormat で要求サンプル数を設定する。これをサポートしていないシステムでは、要求が無視されることがあります。
マルチサンプリングのサポートには、マルチサンプリングされたレンダーバッファとフレームバッファブリットのサポートが必要です。OpenGL ES 2.0の実装では、これらが存在しない可能性が高い。つまり、マルチサンプリングは利用できません。最新のOpenGLバージョンとOpenGL ES 3.0以上では、通常、この問題はなくなります。
スレッド化
例えば、paintGL() の GUI/メインスレッドで使用されるテクスチャを生成するために、ワーカースレッドでオフスクリーンレンダリングを実行することは、ウィジェットのQOpenGLContext を公開することによってサポートされ、それと共有する追加のコンテキストを各スレッドで作成することができます。
GUI/メイン・スレッドの外でQOpenGLWidgetのフレーム・バッファに直接描画することは、paintEvent ()を何もしないように再実装することで可能です。コンテキストのスレッド・アフィニティは、QObject::moveToThread() によって変更する必要があります。その後、makeCurrent() とdoneCurrent() はワーカースレッドで使用できる。その後、コンテキストをGUI/メイン・スレッドに戻すように注意してください。
QOpenGLWidgetのためにバッファ・スワップをトリガーすることはできません。guiスレッドでコンポジションとバッファスワップを管理するのは、ウィジェットスタック次第です。スレッドがフレームバッファを更新し終わったら、GUI/メインスレッドで update ()を呼び出し、合成をスケジュールします。
GUI/メインスレッドが合成を実行しているときにフレームバッファを使用しないように、特に注意が必要です。シグナルaboutToCompose() とframeSwapped() は、コンポジションの開始時と終了時に発せられます。これらはGUI/メインスレッド上で発せられます。つまり、直接接続aboutToCompose() を使用することで、ワーカースレッドがレンダリングを終了するまで、GUI/メインスレッドをブロックすることができます。その後、frameSwapped() シグナルが発行されるまで、ワーカースレッドはそれ以上レンダリングを行ってはいけません。これが受け入れられない場合、ワーカースレッドは二重バッファリング機構を実装しなければなりません。これには、スレッドによって完全に制御される代替のレンダーターゲット(例えば、追加のフレームバッファオブジェクト)を使用して描画し、適切なタイミングでQOpenGLWidgetのフレームバッファにブリットすることが含まれます。
コンテキストの共有
複数の QOpenGLWidget が同じトップレベルのウィジェットの子ウィジェットとして追加されると、それらのコンテキストは互いに共有されます。これは、異なるウィンドウに属するQOpenGLWidgetインスタンスには適用されません。
つまり、同じウィンドウ内のすべてのQOpenGLWidgetは、テクスチャのような共有可能なリソースにアクセスすることができます。
異なるウィンドウに属する QOpenGLWidget インスタンス間の共有を設定するには、QApplication をインスタンス化する前にQt::AA_ShareOpenGLContexts アプリケーション属性を設定します。これにより、それ以上の手順を踏むことなく、すべての QOpenGLWidget インスタンス間で共有が開始されます。
テクスチャなどのリソースをQOpenGLWidgetのコンテキストと共有する、追加のQOpenGLContext インスタンスを作成することも可能です。QOpenGLContext::create ()を呼び出す前に、context ()から返されたポインタをQOpenGLContext::setShareContext ()に渡すだけです。結果として得られるコンテキストは別のスレッドで使用することもでき、テクスチャのスレッド生成やテクスチャの非同期アップロードが可能になります。
QOpenGLWidgetは、基礎となるグラフィックドライバに関して、リソース共有の標準準拠の実装を期待していることに注意してください。例えば、いくつかのドライバ、特にモバイルや組み込みハードウェア用のドライバは、既存のコンテキストと後から作成された他のコンテキストとの間の共有の設定に問題があります。また、異なるスレッド間で共有リソースを利用しようとすると、予期しない動作をするドライバもあります。
リソースの初期化とクリーンアップ
QOpenGLWidgetの関連するOpenGLコンテキストは、initializeGL ()とpaintGL ()が呼び出されるたびに、現在であることが保証されます。initializeGL() が呼び出される前に OpenGL リソースを作成しようとしないでください。たとえば、シェーダーをコンパイルしたり、頂点バッファ・オブジェクトを初期化したり、テクスチャー・データをアップロードしようとすると、サブクラスのコンストラクタで実行されたときに失敗します。これらの操作は、initializeGL() に先送りする必要があります。QtのOpenGLヘルパークラスの中には、QOpenGLBuffer やQOpenGLVertexArrayObject のように、同じように遅延させる動作をするものがあります。これらはコンテキストなしでインスタンス化できますが、すべての初期化はcreate() や同様の呼び出しがあるまで遅延されます。つまり、これらはQOpenGLWidgetのサブクラスで通常の(ポインタでない)メンバ変数として使用できますが、create ()または同様の関数はinitializeGL ()からしか呼び出せません。しかし、すべてのクラスがこのように設計されているわけではないことに注意してください。疑わしい場合は、メンバ変数をポインタにし、initializeGL() とデストラクタでそれぞれ動的にインスタンスを生成および破棄してください。
また、リソースを解放するには、コンテキストがカレントである必要があります。そのため、このようなクリーンアップを行うデストラクタは、OpenGLリソースやラッパーの破棄に移る前に、makeCurrent ()を呼び出すことが期待されています。deleteLater()やQObject の親メカニズムによる遅延削除は避けてください。問題のインスタンスが本当に破棄される時点で、正しいコンテキストがカレントである保証はありません。
したがって、典型的なサブクラスは、リソースの初期化と破棄に関して、以下のようになることがよくあります:
class MyGLWidget : public QOpenGLWidget { ... private: QOpenGLVertexArrayObject m_vao; QOpenGLBuffer m_vbo; QOpenGLShaderProgram *m_program; QOpenGLShader *m_shader; QOpenGLTexture *m_texture; }; MyGLWidget::MyGLWidget() : m_program(0), m_shader(0), m_texture(0) { // No OpenGL resource initialization is done here. } MyGLWidget::~MyGLWidget() { // Make sure the context is current and then explicitly // destroy all underlying OpenGL resources. makeCurrent(); delete m_texture; delete m_shader; delete m_program; m_vbo.destroy(); m_vao.destroy(); doneCurrent(); } void MyGLWidget::initializeGL() { m_vao.create(); if (m_vao.isCreated()) m_vao.bind(); m_vbo.create(); m_vbo.bind(); m_vbo.allocate(...); m_texture = new QOpenGLTexture(QImage(...)); m_shader = new QOpenGLShader(...); m_program = new QOpenGLShaderProgram(...); ... }
これはほとんどのケースで機能しますが、一般的なソリューションとしては完全には理想的ではありません。ウィジェットが全く別のトップレベル・ウィンドウになるようにリペアレントされる場合、さらに何かが必要です。QOpenGLContext のaboutToBeDestroyed() シグナルに接続することで、OpenGLコンテキストが解放されそうになるたびにクリーンアップを実行できます。
注: ウィジェットが生きている間に、関連するトップレベル・ウィンドウを複数回変更する場合、以下のコード・スニペットで示されているように、複合的なクリーンアップ・アプローチが不可欠です。ウィジェットまたはその親が再ペアレントされ、トップレベル・ウィンドウが変わるたびに、ウィジェットの関連コンテキストが破棄され、新しいコンテキストが作成されます。この後、initializeGL()が呼び出され、すべてのOpenGLリソースが再初期化されなければなりません。このため、適切なクリーンアップを実行する唯一の選択肢は、コンテキストのaboutToBeDestroyed()シグナルに接続することです。シグナルが発信されたとき、問題のコンテキストは現在のコンテキストではないかもしれないことに注意してください。したがって、接続されたスロットでmakeCurrent ()を呼び出すのがよい方法です。さらに、シグナルに接続されたスロットやラムダは、ウィジェットが破棄されるときに呼び出されないかもしれないので、派生クラスのデストラクタから同じクリーンアップ手順を実行する必要があります。
MyGLWidget::~MyGLWidget() { cleanup(); } void MyGLWidget::initializeGL() { ... connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &MyGLWidget::cleanup); } void MyGLWidget::cleanup() { makeCurrent(); delete m_texture; m_texture = 0; ... doneCurrent(); disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &MyGLWidget::cleanup); }
注意: Qt::AA_ShareOpenGLContexts が設定されると、ウィジェットのコンテキストは決して変更されません。ウィジェットの関連するテクスチャは、新しいトップレベルのコンテキストからもアクセスできるようになるので、再ペアレントするときでさえも変更されません。したがって、コンテキストのaboutToBeDestroyed()シグナルで動作することは、このフラグが設定されていても必須ではありません。
適切なクリーンアップは、コンテキストの共有のために特に重要である。各QOpenGLWidgetの関連するコンテキストがQOpenGLWidgetと一緒に破棄されても、テクスチャのようなそのコンテキスト内の共有可能なリソースは、QOpenGLWidgetが住んでいたトップレベルのウィンドウが破棄されるまで有効です。さらに、Qt::AA_ShareOpenGLContexts やいくつかの Qt モジュールのような設定によって、コンテキストの共有範囲がさらに広くなり、アプリケーションのライフタイム全体にわたって、問題のリソースが生き続ける可能性があります。したがって、最も安全で堅牢な方法は、QOpenGLWidgetで使用されているすべてのリソースとリソースラッパーを明示的にクリーンアップすることです。
制限とその他の考慮事項
QOpenGLWidgetの下に他のウィジェットを置き、QOpenGLWidgetを透明にすることは、期待される結果につながりません:下のウィジェットは見えなくなります。これは、実際には、QOpenGLWidgetは、他のすべての通常の非OpenGLウィジェットよりも先に描画されるため、シースルータイプのソリューションは実現不可能だからです。QOpenGLWidgetの上にウィジェットを置くような他のタイプのレイアウトは、期待通りに機能します。
どうしても必要な場合は、QOpenGLWidgetにQt::WA_AlwaysStackOnTop 属性を設定することで、この制限を克服できます。例えば、QOpenGLWidgetの上に他のウィジェットを置くことができなくなるので、下に他のウィジェットが見える半透明のQOpenGLWidgetが必要な状況でのみ使用する必要があります。
これは、下に他のウィジェットがなく、半透明のウィンドウを意図している場合には適用されないことに注意してください。この場合、トップレベル・ウィンドウにQt::WA_TranslucentBackground を設定する従来の方法で十分です。透明な領域がQOpenGLWidgetでのみ必要な場合は、Qt::WA_TranslucentBackground を有効にした後、Qt::WA_NoSystemBackground をfalse
に戻す必要があることに注意してください。さらに、システムによっては、setFormat ()を介してQOpenGLWidgetのコンテキストにアルファチャンネルを要求することも必要かもしれません。
QOpenGLWidget は、QOpenGLWindow と同様に、複数の更新動作をサポートしています。保存モードでは、前のpaintGL() 呼び出しからレンダリングされたコンテンツは、次の呼び出しで利用可能であり、インクリメンタルなレンダリングが可能です。非保存モードでは、コンテンツは失われ、paintGL() の実装は、ビュー内のすべてを再描画することが期待されます。
Qt 5.5以前のQOpenGLWidgetのデフォルトの動作は、paintGL()呼び出しの間にレンダリングされた内容を保存することでした。Qt 5.5以降、デフォルトの動作は非保存になりました。この方がパフォーマンスが向上し、大半のアプリケーションは以前のコンテンツを必要としないからです。これは、OpenGLベースのQWindow のセマンティクスにも似ており、QOpenGLWindow のデフォルトの動作である、各フレームで色と補助的なバッファが無効化されるという点でも一致しています。保存された動作を復元するには、PartialUpdate
を使用してsetUpdateBehavior() を呼び出します。
注意: QOpenGLWidgetをウィジェット階層に動的に追加するとき、たとえば、対応するトップレベルのウィジェットがすでに画面上に表示されているウィジェットに新しいQOpenGLWidgetをペアレントすることによって、QOpenGLWidgetがそのウィンドウ内でその種の最初のものである場合、関連するネイティブウィンドウが暗黙的に破棄され、再作成されることがあります。これは、ウィンドウの種類がRasterSurface からOpenGLSurface に変わり、プラットフォーム固有の影響があるためです。この動作はQt 6.4の新機能です。
QOpenGLWidgetがウィジェット階層に追加されると、トップレベルのウィンドウの内容はOpenGLベースのレンダリングによってフラッシュされます。QOpenGLWidget以外のウィジェットは、ソフトウェアベースのペインターを使ってコンテンツを描画し続けますが、最終的な合成は3D APIを通して行われます。
QWidget注意: QOpenGLWidgetを表示するには、関連するトップレベル・ウィンドウのバッキング・ストアにアルファ・チャンネルが必要です。アルファチャンネルがない場合、QOpenGLWidgetによってレンダリングされたコンテンツは表示されません。これは、Linux/X11のリモート・ディスプレイ・セットアップ(Xvncなど)で、24より低い色深度を使用している場合に特に関連する可能性があります。例えば、色深度16は通常、QImage::Format_RGB16 (RGB565)フォーマットのバッキングストア画像を使用することになり、アルファチャンネルを入れる余地がありません。したがって、QOpenGLWidgetの内容がウィンドウ内の他のウィジェットと正しく合成されない場合は、サーバ(vncserverなど)のビット深度が16ではなく、24または32ビットで設定されていることを確認してください。
代替方法
QOpenGLWidgetをウィンドウに追加すると、ウィンドウ全体のOpenGLベースの合成が有効になります。いくつかの特殊なケースでは、これは理想的ではなく、独立したネイティブの子ウィンドウを持つ古いQGLWidgetスタイルの動作が望まれます。このアプローチの限界(オーバーラップ、透明度、スクロールビュー、MDIエリアなど)を理解しているデスクトップアプリケーションは、QWidget::createWindowContainer ()を使ってQOpenGLWindow 。これはQGLWidgetの現代的な代替であり、追加の合成ステップがないため、QOpenGLWidgetよりも高速です。この方法の使用は、他に選択肢がない場合に限定することを強く推奨します。このオプションは、ほとんどの組み込みプラットフォームやモバイルプラットフォームには適しておらず、特定のデスクトッププラットフォーム(例えばmacOS)でも問題があることが知られていることに注意してください。安定したクロスプラットフォームのソリューションは、常にQOpenGLWidgetです。
ステレオスコピックレンダリング
6.5以降、QOpenGLWidgetはステレオスコピックレンダリングをサポートしています。これを有効にするには、QSurfaceFormat::SetDefaultFormat() を使用して、ウィンドウが作成される前にQSurfaceFormat::StereoBuffers フラグをグローバルに設定します。
注意: setFormat() を使用しても、フラグが内部的に処理されるため、必ずしも動作するとは限りません。
QOpenGLWidget::TargetBufferこの場合、paintGL() が各フレームごとに 2 回呼び出されます。paintGL() では、currentTargetBuffer() を呼び出して、現在描画されているのがどれであるかを問い合わせます。
注意: 左右のカラーバッファをより細かく制御するには、代わりにQOpenGLWindow +QWidget::createWindowContainer() を使用することを検討してください。
注: このタイプの 3D レンダリングには、グラフィックスカードがステレオをサ ポートするようにセットアップされている必要があるなど、特定のハードウェア要 件があります。
OpenGL は、米国およびその他の国における Silicon Graphics, Inc.の商標です。
QOpenGLFunctions 、QOpenGLWindow 、Qt::AA_ShareOpenGLContexts 、UpdateBehaviorも参照 。
メンバータイプ ドキュメント
[since 6.5]
enum QOpenGLWidget::TargetBuffer
ステレオスコピックレンダリングが有効になっているときに使用するバッファを指定します。これはQSurfaceFormat::StereoBuffers を設定することで切り替わります。
注: LeftBuffer は常にデフォルトであり、立体視レンダリングが無効またはグラフィックドライバによってサポートされていない場合のフォールバック値として使用されます。
定数 | 値 |
---|---|
QOpenGLWidget::LeftBuffer | 0 |
QOpenGLWidget::RightBuffer | 1 |
この列挙型は Qt 6.5 で導入されました。
enum QOpenGLWidget::UpdateBehavior
この列挙型は、QOpenGLWidget の更新セマンティクスを記述します。
定数 | 値 | 説明 |
---|---|---|
QOpenGLWidget::NoPartialUpdate | 0 | QOpenGLWidget は、 がスクリーンにレンダリングされた後、カラーバッファと補助バッファの内容を破棄します。これは、デフォルトのopenglが有効な を引数として を呼び出すことで期待できる動作と同じです。フレームバッファオブジェクトがレンダリングターゲットとして使用される場合、NoPartialUpdateは、モバイルや組み込みの領域で一般的な特定のハードウェアアーキテクチャ上でいくつかのパフォーマンス上の利点を持つことができます。フレームバッファオブジェクトは、glInvalidateFramebuffer(サポートされている場合)、またはフォールバックとして、glDiscardFramebufferEXT(サポートされている場合)、またはglClearの呼び出しによってフレーム間で無効にされます。QOpenGLWidget QWindow QOpenGLContext::swapBuffers |
QOpenGLWidget::PartialUpdate | 1 | フレームバッファオブジェクトのカラーバッファと補助バッファは、フレーム間で無効化されません。 |
updateBehavior() およびsetUpdateBehavior()も参照 。
メンバ関数ドキュメント
[explicit]
QOpenGLWidget::QOpenGLWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags())
ウィジェットフラグがf に設定されたparent の子ウィジェットを構築します。
[virtual noexcept]
QOpenGLWidget::~QOpenGLWidget()
QOpenGLWidget インスタンスを破棄し、リソースを解放する。
QOpenGLWidget のコンテキストはデストラクタでカレントとなり、このウィジェットが提供するコンテキストに属する OpenGL リソースを解放する必要があるかもしれない子オブジェクトを安全に破壊することができます。
警告: OpenGLWidgetサブクラスのメンバとしてOpenGLリソースをラップしているオブジェクト(QOpenGLBuffer 、QOpenGLShaderProgram など)がある場合、そのサブクラスのデストラクタにもmakeCurrent ()の呼び出しを追加する必要があるかもしれません。C++のオブジェクト破棄のルールにより、これらのオブジェクトはこの関数を呼び出す前に破棄されます(ただし、サブクラスのデストラクタが実行された後)。したがって、この関数でOpenGLコンテキストをカレントにしてしまうと、安全に破棄するには遅すぎます。
makeCurrentも参照してください 。
[signal]
void QOpenGLWidget::aboutToCompose()
このシグナルは、ウィジェットのトップレベルウィンドウが、そのQOpenGLWidget 子ウィジェットと他のウィジェットのテクスチャの合成を開始しようとするときに発せられます。
[signal]
void QOpenGLWidget::aboutToResize()
このシグナルは、ウィジェットのサイズが変更され、フレームバッファオブジェクトが再作成されるときに発行されます。
QOpenGLContext *QOpenGLWidget::context() const
Returns このウィジェットによって使われるQOpenGLContext か、まだ初期化されていない場合は0
を返します。
注意: setParent() によってウィジェットを再ペアレントするとき、ウィジェットによって使用されるコンテキストとフレームバッファオブジェクトは変更されます。
QOpenGLContext::setShareContext() およびdefaultFramebufferObject()も参照してください 。
[since 6.5]
QOpenGLWidget::TargetBuffer QOpenGLWidget::currentTargetBuffer() const
現在アクティブなターゲットバッファを返します。これはデフォルトでは左バッファとなり、右バッファはQSurfaceFormat::StereoBuffers が有効な場合にのみ使用されます。立体視レンダリングが有効になっている場合、paintGL() でこの値を問い合わせることで、現在使用されているバッファを知ることができます。paintGL() は、各ターゲットに対して 1 回ずつ、2 回呼び出されます。
この関数は Qt 6.5 で導入されました。
paintGL()も参照してください 。
GLuint QOpenGLWidget::defaultFramebufferObject() const
戻り値 フレームバッファオブジェクトのハンドル、またはまだ初期化されていない場合は0
を返します。
注意: フレームバッファオブジェクトは、context ()によって返されたコンテキストに属しており、他のコンテキストからはアクセスできない可能性があります。
注意 :setParent() によってウィジェットを再ペアレントすると、ウィジェットによって使用されるコンテキストとフレームバッファオブジェクトが変更されます。また、フレームバッファオブジェクトは、リサイズのたびに変更されます。
context()も参照してください 。
[since 6.5]
GLuint QOpenGLWidget::defaultFramebufferObject(QOpenGLWidget::TargetBuffer targetBuffer) const
戻り値 指定されたターゲットバッファのフレームバッファオブジェクトハンドル、または、まだ初期化されていない場合は、0
。
このオーバーロードを呼び出すことは、QSurfaceFormat::StereoBuffers が有効でハードウェアによってサポートされている場合にのみ意味があります。そうでない場合、このメソッドはデフォルトのバッファを返します。
注意: フレームバッファオブジェクトは、context ()によって返されたコンテキストに属しており、他のコンテキストからはアクセスできない場合があります。ウィジェットによって使用されるコンテキストとフレームバッファオブジェクトは、setParent ()を介してウィジェットを再ペアレントするときに変更されます。さらに、フレームバッファオブジェクトは、リサイズのたびに変更されます。
この関数は Qt 6.5 で導入されました。
context()も参照してください 。
void QOpenGLWidget::doneCurrent()
コンテキストを解放します。
ほとんどの場合、この関数を呼び出す必要はありません。ウィジェットは、paintGL() を呼び出すときに、コンテキストが適切にバインドされ、解放されることを確認するからです。
[override virtual protected]
bool QOpenGLWidget::event(QEvent *e)
再実装:QWidget::event(QEvent *event)。
QSurfaceFormat QOpenGLWidget::format() const
このウィジェットとそのトップレベルウィンドウで使用されるコンテキストとサーフェスフォーマットを返します。
ウィジェットとそのトップレベルが共に作成され、サイズが変更され、表示された後、この関数はコンテキストの実際のフォーマットを返します。要求がプラットフォームによって満たされなかった場合、これは要求されたフォーマットと異なるかもしれない。また、要求されたよりも大きなカラーバッファサイズを得ることも可能である。
ウィジェットのウィンドウと関連するOpenGLリソースがまだ初期化されていない場合、戻り値はsetFormat() で設定されたフォーマットです。
[signal]
void QOpenGLWidget::frameSwapped()
このシグナルは、ウィジェットのトップレベル・ウィンドウがコンポジションを終了し、ブロッキングの可能性のあるQOpenGLContext::swapBuffers() 呼び出しから戻った後に発行されます。
QImage QOpenGLWidget::grabFramebuffer()
フレームバッファの 32 ビット RGB 画像をレンダリングして返します。
注意: これは、ピクセルを読み出すために glReadPixels() に依存するため、潜在的に高価な操作です。これは遅く、GPUパイプラインを停止させる可能性があります。
[since 6.5]
QImage QOpenGLWidget::grabFramebuffer(QOpenGLWidget::TargetBuffer targetBuffer)
指定されたターゲットバッファのフレームバッファの 32 ビット RGB 画像をレンダリングして返します。このオーバーロードは、QSurfaceFormat::StereoBuffers が有効な場合にのみ呼び出す意味があります。ステレオスコピックレンダリングが無効になっているか、ハードウェアでサ ポートされていない場合、右のターゲットバッファのフレームバッファをグ ラブすると、デフォルトの画像が返されます。
注意: これは、ピクセルを読み戻すために glReadPixels() に依存するため、潜在的に高価な操作です。これは遅く、GPU パイプラインを停止させる可能性があります。
この関数は Qt 6.5 で導入されました。
[virtual protected]
void QOpenGLWidget::initializeGL()
この仮想関数は、paintGL() またはresizeGL() を最初に呼び出す前に一度呼び出されます。サブクラスで再実装してください。
この関数は必要なOpenGLリソースを設定する。
この関数が呼ばれたときにすでに設定されているので、makeCurrent ()を呼び出す必要はない。ただし、この段階ではフレームバッファはまだ利用できないので、ここから描画コールを発行するのは避けてください。このような呼び出しは、paintGL() に回してください。
paintGL() およびresizeGL()も参照してください 。
bool QOpenGLWidget::isValid() const
コンテキストのようなウィジェットとOpenGLリソースが正常に初期化された場合、trueを返します。ウィジェットが表示されるまでは、戻り値は常にfalseであることに注意。
void QOpenGLWidget::makeCurrent()
対応するコンテキストをカレントにし、そのコンテキストでフレームバッファオブジェクトをバインドすることによって、このウィジェットのOpenGLコンテンツのレンダリングを準備する。
この関数は、paintGL ()を呼び出す前に自動的に呼び出されるため、ほとんどの場合、この関数を呼び出す必要はありません。
context ()、paintGL ()、doneCurrent ()も参照 。
[since 6.5]
void QOpenGLWidget::makeCurrent(QOpenGLWidget::TargetBuffer targetBuffer)
渡されたバッファのコンテキストをカレントにし、フレームバッファオブジェクトをそのコンテキストにバインドすることで、このウィジェットの OpenGL コンテンツのレンダリングを準備します。
注意: これは、ステレオスコピックレンダリングが有効になっているときにのみ呼び出す意味があります。無効になっているときに正しいバッファが要求されても何も起こりません。
この関数はpaintGL() を呼び出す前に自動的に呼び出されるため、ほとんどの場合、この関数を呼び出す必要はありません。
この関数は Qt 6.5 で導入されました。
context(),paintGL(),doneCurrent()も参照してください 。
[override virtual protected]
int QOpenGLWidget::metric(QPaintDevice::PaintDeviceMetric metric) const
再実装:QWidget::metric(QPaintDevice::PaintDeviceMetric m) const.
[override virtual protected]
QPaintEngine *QOpenGLWidget::paintEngine() const
再リンプルメント: (QPaintDevice::PaintDeviceMetric m) const:QWidget::paintEngine() const.
[override virtual protected]
void QOpenGLWidget::paintEvent(QPaintEvent *e)
Reimplements: (QPaintDevice::PaintDeviceMetric m) const:QWidget::paintEvent(QPaintEvent *event)。
ペイントイベントを処理します。
QWidget::update() を呼び出すと、ペイントイベントがe に送信され、この関数が呼び出されます。(注意: これは非同期で、update() から戻った後に発生します)。この関数は、いくつかの準備の後、仮想paintGL() を呼び出してQOpenGLWidget のフレームバッファの内容を更新します。ウィジェットのトップレベルウィンドウは、フレームバッファのテクスチャをウィンドウの残りの部分と合成します。
[virtual protected]
void QOpenGLWidget::paintGL()
この仮想関数は、ウィジェットをペイントする必要があるときはいつでも呼び出されます。サブクラスで再実装してください。
この関数が呼び出されたときにすでに実行されているので、makeCurrent ()を呼び出す必要はありません。
この関数を呼び出す前に、コンテキストとフレームバッファがバインドされ、glViewport()の呼び出しによってビューポートがセットアップされます。他の状態は設定されず、クリアや描画はフレームワークによって実行されない。
デフォルトの実装は glClear() を実行します。サブクラスは基底クラスの実装を呼び出すことは期待されておらず、それ自身でクリアを実行する必要があります。
注意: 移植性を確保するために、initializeGL() で設定された状態が持続することを期待しないでください。むしろ、例えば paintGL()の中で glEnable()を呼び出すなどして、必要な状態をすべて設定してください。これは、WebGLを使用するWebAssemblyのようないくつかのプラットフォームでは、状況によってはOpenGLコンテキストに制限がある場合があり、QOpenGLWidget で使用されるコンテキストを他の目的にも使用することにつながる可能性があるためです。
QSurfaceFormat::StereoBuffers が有効な場合、この関数は2回呼び出されます-各バッファに対して1回ずつ。どのバッファが現在バインドされているかは、currentTargetBuffer() を呼び出すことで確認できます。
注意: 立体視レンダリングがハードウェアでサポートされていない場合でも、 各ターゲットのフレームバッファに描画されます。実際にウィンドウに表示されるのは左のバッファだけです。
initializeGL()、resizeGL()、currentTargetBuffer()も参照 。
[override virtual protected]
QPaintDevice *QOpenGLWidget::redirected(QPoint *p) const
[override virtual protected]
void QOpenGLWidget::resizeEvent(QResizeEvent *e)
再実装:QWidget::resizeEvent(QResizeEvent *event)。
e event パラメータで渡されるリサイズイベントを処理します。仮想関数resizeGL() を呼び出します。
注意: 派生クラスでこの関数をオーバーライドすることは避けてください。それが不可能な場合は、QOpenGLWidget の実装も呼び出されるようにしてください。そうしないと、フレームバッファオブジェクトと関連リソースのサイズが正しく変更されず、レンダリングが正しく行われません。
[virtual protected]
void QOpenGLWidget::resizeGL(int w, int h)
この仮想関数は、ウィジェットのサイズが変更されるたびに呼び出されます。サブクラスで再実装してください。新しいサイズはw とh で渡されます。
makeCurrent() を呼び出す必要はありません。なぜなら、この関数が呼び出されたときに、すでにこの処理が行われているからです。さらに、フレームバッファもバインドされます。
initializeGL() およびpaintGL()も参照 。
[signal]
void QOpenGLWidget::resized()
このシグナルは、ウィジェットのサイズ変更によってフレームバッファオブジェクトが再作成された直後に発行されます。
void QOpenGLWidget::setFormat(const QSurfaceFormat &format)
要求されたサーフェスformat を設定します。
この関数によってフォーマットが明示的に設定されない場合、QSurfaceFormat::defaultFormat() によって返されたフォーマットが使用されます。つまり、複数の OpenGL ウィジェットがある場合、この関数を個別に呼び出す代わりに、最初のウィジェットを作成する前にQSurfaceFormat::setDefaultFormat() を 1 回呼び出すことができます。
注意: 他のウィジェットを下に表示させることを意図している場合、この関数でアルファ・バッファを要求しても望ましい結果は得られません。代わりに、Qt::WA_AlwaysStackOnTop を使用して、下に他のウィジェットが見える半透明のQOpenGLWidget インスタンスを有効にします。ただし、これは積み重ねの順序を壊すので、QOpenGLWidget の上に他のウィジェットを置くことができなくなることに注意してください。
format(),Qt::WA_AlwaysStackOnTop,QSurfaceFormat::setDefaultFormat()も参照してください 。
void QOpenGLWidget::setTextureFormat(GLenum texFormat)
texFormat のカスタム内部テクスチャフォーマットを設定します。
sRGB フレームバッファを扱う場合は、GL_SRGB8_ALPHA8
のようなフォーマットを指定する必要があります。これは、この関数を呼び出すことで実現できます。
Note: この関数は、ウィジェットが既に表示され、初期化が行われた後に呼び出されても、何の効果もありません。
注意: この関数は通常、色空間をQSurfaceFormat::sRGBColorSpace に設定するQSurfaceFormat::setDefaultFormat() と組み合わせて使用する必要がある。
textureFormat()も参照 。
void QOpenGLWidget::setUpdateBehavior(QOpenGLWidget::UpdateBehavior updateBehavior)
このウィジェットの更新動作をupdateBehavior に設定する。
updateBehavior() も参照して ください。
GLenum QOpenGLWidget::textureFormat() const
ウィジェットがすでに初期化されている場合はアクティブな内部テクスチャフォーマットを、フォーマットが設定されているがウィジェットがまだ可視化されていない場合は要求されたフォーマットを、setTextureFormat() が呼び出されておらずウィジェットがまだ可視化されていない場合はnullptr
を返します。
setTextureFormat()も参照 。
QOpenGLWidget::UpdateBehavior QOpenGLWidget::updateBehavior() const
ウィジェットの更新動作を返します。
setUpdateBehavior() も参照して ください。
©2024 The Qt Company Ltd. 本文書に含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。