このページについて

Qt 3D 概要

Qt 3D は、開発者が必要なあらゆるレンダリングパイプラインを迅速に実装できるようにする、完全に設定可能なレンダラーを提供します。さらに、Qt 3D は、レンダリングを超えたニアリアルタイムシミュレーションのための汎用フレームワークを提供します。

Qt 3D は、コアと、任意の機能を実装できる任意の数のアスペクトに明確に分離されています。アスペクトはコンポーネントやエンティティと連携し、特定の機能を提供します。アスペクトの例としては、物理演算、オーディオ、衝突判定、人工知能(AI)、経路探索などが挙げられます。

基本的な3D機能

Qt 3D は、3D形状の描画や移動、およびカメラの移動を可能にする3Dフレームワークです。以下の基本機能をサポートしています:

マテリアル

Qt 3D には、堅牢かつ非常に柔軟なマテリアルシステムが備わっており、多段階にわたるカスタマイズが可能です。このシステムは、プラットフォームやOpenGLのバージョンに応じたさまざまなレンダリング手法に対応し、異なるステートセットを用いた複数のレンダリングパスを可能にし、さまざまなレベルでのパラメータ上書きメカニズムを提供し、シェーダーの切り替えを容易にします。これらすべてをC++またはQMLのプロパティバインディングを使用して実現できます。

Material 型のプロパティは、参照されるエフェクトプロパティ内で指定されたGLSLシェーダープログラム内のユニフォーム変数に、簡単にマッピングできます。

マテリアルの使用例については、以下の例を参照してください:

シェーダー

Qt 3D は、OpenGLのプログラム可能なレンダリングパイプラインのすべてのステージ(頂点シェーダー、テッセレーション制御シェーダー、テッセレーション評価シェーダー、ジオメトリシェーダー、フラグメントシェーダー)をサポートしています。コンピュートシェーダーは今後のリリースで実装される予定です。

シェーダーの使用例については、「Qt 3D :ワイヤーフレーム QML サンプル」を参照してください。

シャドウマッピング

OpenGL では影は直接サポートされていませんが、影を生成するために採用できる手法は数え切れないほどあります。シャドウマッピングは、パフォーマンスへの負荷を最小限に抑えつつ、見栄えの良い影を生成するのに簡単に利用できます。

シャドウマッピングは通常、2パスレンダリングを用いて実装されます。第1パスでは、影の情報が生成されます。第2パスでは、特定のレンダリング手法を用いてシーンを生成すると同時に、第1パスで収集した情報を用いて影を描画します。

シャドウマッピングの背後にある考え方は、光源に最も近いフラグメントのみが照らされるというものです。他のフラグメントの後ろにあるフラグメントは遮蔽されるため、影になります。

したがって、第1パスでは、シーンは光源の視点から描画されます。保存される情報は、この光空間における最も近いフラグメントまでの距離に他なりません。 OpenGLの用語で言えば、これは深度テクスチャがアタッチされたフレームバッファオブジェクト(FBO)を持つことに相当します。実際、目からの距離こそが深度の定義であり、OpenGLが行うデフォルトの深度テストでは、実際には最も近いフラグメントの深度のみが保存されます。

フラグメントのシェーディングを行う必要はなく、深度を計算するだけで済むため、カラーテクスチャのアタッチメントすら必要ありません。

次の画像は、自己影を持つ平面と三葉結び目を含むシーンを示しています:

緑色の平面の上に金属色の結び目が浮かび、背景にはオレンジ色の飛行機が飛んでいる様子を描いた3Dレンダリング画像

次の画像は、このシーンの影マップテクスチャを誇張して示したものです:

3Dの結び目と飛行機のグレースケール深度マップ

この画像は、光源の視点からシーンをレンダリングした際に保存される深度を示しています。 色が濃いほど深度が浅い(つまり、カメラに近い)ことを表しています。このシーンでは、光源はシーン内のオブジェクトの上方、メインカメラから見て右側に配置されています(最初のスクリーンショットと比較してください)。これは、おもちゃの平面が他のオブジェクトよりもカメラに近いという事実と一致しています。

シャドウマップが生成されると、2回目のレンダリングパスが実行されます。この2回目のパスでは、通常のシーンのカメラを使用してレンダリングが行われます。 ここでは、フォンシェーディングなど、任意のエフェクトを使用できます。重要なのは、フラグメントシェーダーでシャドウマップアルゴリズムを適用することです。つまり、光源に最も近いフラグメントは光が当たった状態で描画され、その他のフラグメントは影として描画されます。

第1パスで生成されたシャドウマップは、フラグメントと光源との距離に関する必要な情報を提供します。その後、フラグメントをライト空間に再マッピングするだけで十分であり、それによって光源からの視点での深度、およびシャドウマップテクスチャ上の座標位置を算出できます。 その後、指定された座標でシャドウマップテクスチャをサンプリングし、フラグメントの深度をサンプリング結果と比較します。フラグメントがサンプリング位置より遠い場合は影になり、そうでない場合は照らされた状態になります。

インスタンス化レンダリング

インスタンス化とは、ベースオブジェクトの多くのコピー(インスタンス)を、コピーごとに何らかの点で変化させてGPUに描画させる手法です。多くの場合、位置、向き、色、マテリアル特性、スケールなどが変化します。Qt 3D は、Qt Quick のRepeater 要素に類似したAPIを提供します。 この場合、デリゲートがベースオブジェクトとなり、モデルがインスタンスごとのデータを提供します。つまり、Mesh コンポーネントがアタッチされたエンティティは最終的にglDrawElementsへの呼び出しに変換されるのに対し、instancedコンポーネントを持つエンティティはglDrawElementsInstancedへの呼び出しに変換されます。

インスタンス化されたレンダリングは、将来のリリースで実装される予定です。

ユニフォーム・バッファ・オブジェクト

ユニフォーム・バッファ・オブジェクト(UBO)を OpenGL シェーダ・プログラムにバインドすることで、大量のデータを即座に利用可能にすることができます。UBO の代表的な使用例としては、マテリアルや照明パラメータのセットが挙げられます。

役立つヒント

3D レンダリングに関する非常に役立つプログラミングのヒントは、次のページでご覧いただけます:Qt 3D Render Pro Tips。

設定可能なレンダラー

C++ および QML API の両方をサポートしつつ、完全に設定可能なレンダラーを実現するために、フレームグラフという概念が導入されました。シーングラフが「何をレンダリングするか」をデータ駆動的に記述するものであるのに対し、フレームグラフは「どのようにレンダリングするか」をデータ駆動的に記述するものです。

フレームグラフを使用することで、開発者は、Zフィルパスを含む単純なフォワードレンダラーと、例えばディファードレンダラーとのいずれかを選択できるようになります。また、透明なオブジェクトをいつレンダリングするかなどを制御することも可能です。 これらはすべて純粋にデータから設定されるため、C++コードに触れることなく、実行時に動的に変更することも非常に容易です。また、カスタムレンダリングアルゴリズムを実装した独自のフレームグラフを作成することで、Qt 3D を拡張することも可能です。

3D 拡張機能

画面上に3Dコンテンツを表示するという基本機能に加え、Qt 3D は拡張性が高く柔軟であるため、3Dオブジェクトに関連する以下の種類の拡張機能をホストすることができます:

  • 物理シミュレーション
  • 衝突検出
  • 3D 位置依存オーディオ
  • 剛体、スケルトン、およびモーフターゲットによるアニメーション
  • 経路探索およびその他のAI
  • ピック操作
  • パーティクル
  • オブジェクトの生成

パフォーマンス

Qt 3D は、高いパフォーマンスを発揮し、利用可能な CPU コア数に応じてスケーラビリティが向上するように設計されています。これは、現代のハードウェアでは、ベースクロック速度ではなくコア数の増加によってパフォーマンスが向上するためです。多くのタスクは互いに独立しているため、複数のコアを使用することで高いパフォーマンスが得られます。 たとえば、パスファインディングモジュールが実行する操作は、デバッグ情報や統計情報をレンダリングする場合を除いて、レンダラーが実行するタスクと大きく重複することはありません。

Qt 3D アーキテクチャ

Qt 3D の主なユースケースは、オブジェクトをニアリアルタイムでシミュレートし、それらのオブジェクトの状態を画面上にレンダリングすることです。Space Invadersのサンプルには、以下のオブジェクトが含まれています:

『スペースインベーダー』のゲームプレイ画面のスクリーンショット

  • プレイヤーの地上砲
  • 地面
  • 防御ブロック
  • 敵のスペースインベーダー艦
  • 敵のボスである空飛ぶ円盤
  • 敵とプレイヤーが発射する弾

従来のC++設計では、こうした種類のオブジェクトは通常、何らかの継承ツリーとして構成されたクラスとして実装されます。継承ツリーのさまざまな分岐は、次のような機能のためにルートクラスに追加の機能を付加する場合があります:

  • ユーザー入力を受け付ける
  • サウンドを再生する
  • アニメーションの再生
  • 他のオブジェクトと衝突する
  • 画面上に描画される

『スペースインベーダー』の例における型は、これらの特徴に基づいて分類することができます。しかし、このような単純な例であっても、洗練された継承ツリーを設計することは容易ではありません。

このアプローチやその他の継承のバリエーションには、いくつかの問題があります。

  • 深く広範な継承階層は、理解、保守、拡張が困難です。
  • 継承の分類体系はコンパイル時に固定されてしまう。
  • クラス継承ツリーの各レベルでは、単一の基準または軸に基づいてのみ分類を行うことができます。
  • 共有機能は、時間の経過とともにクラス階層の上位へと波及する傾向があります。
  • 開発者が今後何をしたいと思うかを予測することは不可能です。

深くて広範な継承ツリーを拡張するには、通常、元の作成者が使用した分類体系を理解し、それに同意する必要があります。そのため、Qt 3D では、オブジェクトのインスタンスに機能を付与する手段として、継承ではなく集約に重点を置いています。具体的には、Qt 3D はエンティティ・コンポーネント・システム (ECS) を実装しています。

ECS の利用

ECS において、エンティティはシミュレートされるオブジェクトを表しますが、それ自体には特定の挙動や特性は一切持ちません。エンティティが 1 つ以上のコンポーネントを集約させることで、追加の挙動をエンティティに組み込むことができます。各コンポーネントは、オブジェクト型の挙動の垂直的なスライスです。

『スペースインベーダー』の例では、地面はエンティティであり、そのエンティティには、レンダリングが必要であること、およびどのようなレンダリングが必要かをシステムに伝えるコンポーネントがアタッチされています。 敵のスペースインベーダー船もまた、エンティティであり、船をレンダリングさせるだけでなく、サウンドを再生したり、衝突判定を受けたり、アニメーションを表示したり、単純なAIによって制御されたりすることを可能にするコンポーネントがアタッチされています。

プレイヤーの地上砲エンティティは、AIコンポーネントを持たない点を除けば、敵のスペースインベーダー船とほぼ同様のコンポーネントを持っています。その代わりに、砲には、プレイヤーが砲を移動させたり弾を発射したりできるようにする入力コンポーネントが備わっています。

ECSバックエンド

QEntityの構成要素を示す図

『Qt 3D 』のバックエンドは、ECSパラダイムのシステム部分を アスペクトという形で実装しています。アスペクトは、エンティティに提供される機能のうち、1つ以上の集約されたコンポーネントの組み合わせによって構成される特定の垂直スライスを実装します。

例えば、レンダラーアスペクトは、メッシュ、マテリアル、およびオプションでトランスフォーメーションコンポーネントを持つエンティティを探します。レンダラーアスペクトがそのようなエンティティを見つけると、そのデータを取り込んで美しい描画を行う方法を知っています。エンティティがこれらのコンポーネントを持っていない場合、レンダラーアスペクトはそれを無視します。

Qt 3D 追加の機能を提供するコンポーネントを集約することで、カスタムエンティティを構築します。Qt 3D エンジンは、アスペクトを使用して、特定のコンポーネントを持つエンティティを処理および更新します。

例えば、物理アスペクトは、何らかの衝突ボリュームコンポーネントと、質量や摩擦係数など、そのようなシミュレーションに必要なその他のプロパティを指定する別のコンポーネントを持つエンティティを探します。音を発するエンティティには、それがサウンドエミッターであることを指定するコンポーネントに加え、いつ、どの音を再生するかを指定するコンポーネントがあります。

ECSは継承ではなく集約を採用しているため、コンポーネントを追加または削除するだけで、実行時にオブジェクトの挙動を動的に変更することが可能です。

たとえば、パワーアップ後にプレイヤーが突然壁を通り抜けられるようにするには、そのエンティティの衝突ボリュームコンポーネントを、パワーアップの効果が切れるまで一時的に削除すればよい。PlayerWhoRunsThroughWalls のために特別な単発のサブクラスを作成する必要はない。

Qt 3D ECS の実装

Qt 3D は、ECSを単純なクラス階層として実装しています。Qt 3D の基底クラスはQt3DCore::QNodeであり、これはQObject のサブクラスです。Qt3DCore::QNodeは、QObject に対し、プロパティの変更をアスペクトに自動的に通知する機能と、アプリケーション全体で一意なIDを追加します。 アスペクトは追加のスレッド上に存在し、Qt3DCore::QNode は、ユーザー向けのオブジェクトとアスペクト間のデータ転送を簡素化します。

通常、Qt3DCore::QNode のサブクラスは、コンポーネントから参照される追加のサポートデータを提供します。たとえば、QShaderProgram クラスは、一連のエントティをレンダリングする際に使用される GLSL コードを指定します。

QEntity、QComponent、QNode、およびQObjectの関係を示す図

Qt 3D のコンポーネントは、Qt3DCore::QComponent をサブクラス化し、対応するアスペクトが機能するために必要なデータを追加することで実装されます。たとえば、メッシュコンポーネントは、レンダラーアスペクトによって、OpenGL パイプラインに送信されるべき頂点ごとのデータを取得するために使用されます。

最後に、Qt3DCore::QEntity は、0 個以上の Qt3DCore::QComponent インスタンスを集約できる単なるオブジェクトです。

機能の拡張Qt 3D

Qt 3D に機能を追加するには(Qt XMLの一部として、あるいはマルチスレッドのバックエンドを活用するための独自のアプリケーション固有の機能として)、以下のタスクを行います。

  • 必要なコンポーネントとサポートデータを特定し、実装します。
  • QML エンジンにコンポーネントを登録します(QML API を使用する場合のみ)。
  • QAbstractAspect をサブクラス化し、サブシステムの機能を実装します。

Qt 3D タスクベースのエンジン

Qt 3D では、各フレームごとに、アスペクトに対して実行すべきタスクのセットと、それらの間の依存関係が問い合わせられます。パフォーマンスを向上させるため、タスクはスケジューラによって設定されたすべてのコアに分散されます。

Qt 3Dのアスペクト

デフォルトでは、Qt 3D は Qt3DRender および Qt3DInput アスペクトを提供します。これらのアスペクトによって提供されるコンポーネントやその他のサポートクラスについては、各モジュールのドキュメントで説明されています。

Qt 3D の将来のバージョンでは、さらなる機能を提供する追加のアスペクトが追加される予定です。

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.