インスタンス化レンダリング
はじめに
Qt Quick 3Dでは、Model オブジェクトのインスタンス化をサポートしています。インスタンス化とは、1回の描画呼び出しで1つのオブジェクトを複数回レンダリングする手法を指します。(例:OpenGL関数glDrawElementsInstanced 。)
インスタンス化により、バリエーションを持たせたモデルの複製が可能になります。Repeater3D を使用する場合とは対照的に、モデルとそのグラフィックリソースは一度だけ割り当てられます。複製されたインスタンスのレンダリングは、GPUによって低レベルで行われます。モデルの複雑さによっては、これにより数桁のパフォーマンス向上が得られる場合があります。
実際には、インスタンス化は、ベースモデルに対して各インスタンスをどのように変更するかを指定するテーブルを定義することで行われます。
インスタンス化API
インスタンス化APIの主な原則は、その明示性にあります。既存のAPI内でインスタンス化の機会を自動検出しようとはしません。代わりに、各モデルのinstancing プロパティを設定してInstancing オブジェクトを参照させることで、モデルごとに個別にマークします。同じInstancingオブジェクトを複数のモデルで同時に使用することができます。
Instancingオブジェクトは、各コピーがどのようにレンダリングされるかを定義するテーブルを指定します。利用可能な変更項目は以下の通りです:
- transformation: 位置、回転、スケール
- color: モデルのマテリアルとブレンドされる色
- カスタムデータ: カスタムマテリアルで使用できるデータ
Qt Qml には、Instancing を継承する 3 つの QML 型が用意されています:
- InstanceList すべてのインスタンスを列挙し、各インスタンスのプロパティへのバインディングを可能にします。
- RandomInstancing 定義された範囲内でランダムなインスタンスを生成することで、迅速なテストやプロトタイピングを行う手段を提供します。
- FileInstancing 外部ファイルからインスタンステーブルを読み込みます。
インスタンス化の例では、QML API を使用してシーンを作成する方法を示しています。
QQuick3DInstancing をサブクラス化することで、C++で他の種類のインスタンステーブルを定義できます。例えば、particle system は内部で独自のインスタンステーブルを使用しています。これはModelParticle3D.instanceTable として利用可能です。
カスタムシェーダーコードを記述することで、インスタンス化を利用して、物理ベースレンダリングの変数、スケルトンアニメーションのウェイト、歪み、あるいはカスタムマテリアルで表現可能なその他のプロパティを制御することが可能です。インスタンス化テーブル内のカスタムデータは、4つの浮動小数点数で構成されています。
カスタムインスタンス化のサンプルでは、カスタムマテリアルとC++で実装されたインスタンステーブルを組み合わせる方法を示しています。
アルファブレンディングとインスタンス化
正しいアルファブレンディングを行うには、半透明のオブジェクトを後ろから前に向かってレンダリングする必要があります。このため、QtQuick3D は不透明なオブジェクトと半透明なオブジェクトを別々にソートし、正しい順序でレンダリングします。しかし、インスタンス化を使用する場合、「depth-sorting 」がオンになっていないと、GPUはインスタンステーブルで指定された順序でインスタンスをレンダリングしてしまいます。 パフォーマンス上の理由から、QtQuick3D はデフォルトではテーブルのソートを行いません。インスタンスの数が多いと、ソートに時間がかかるためです。つまり、半透明のインスタンス同士、あるいは他の半透明オブジェクトと重なっている場合、結果が不自然に見える可能性があります。一般的に、不透明度が低いほどこの不具合は目立ちにくくなります。
完全に不透明なオブジェクトと、重なり合っていない半透明のオブジェクトは、常に正しくレンダリングされます。これは、Qtが不透明なオブジェクトの背後への描画を避けるために深度バッファテストを使用しているためです。 しかし、ソートが行われないことは、不透明なオブジェクトのパフォーマンスに潜在的な影響を及ぼす可能性があります。それらは最適な順序でレンダリングされない場合があり、その結果、同じピクセルが複数回書き込まれることになり、フラグメントシェーダーの負荷が増大する可能性があります。
レンダラーはインスタンステーブルの内容を検査しないため、インスタンステーブルに半透明のアルファ値が含まれている場合は、明示的に指定する必要があります。レンダラーがアルファブレンディングを有効にするようにするには、hasTransparency プロパティをtrue に設定してください。これはすべてのインスタンスに適用されます。完全に不透明なインスタンスでさえ、深度テストなしでレンダリングされ、目に見えるエラーが発生する可能性があります。
シーン内の他のオブジェクトに対するレンダリング順序は、モデルのdepth bias を設定することで調整できます。
トランスフォームとインスタンス化
各インスタンスは、インスタンステーブル内で独自のトランスフォームを持ちます。これは、インスタンス化されたモデルへのトランスフォームと組み合わされます。これにはいくつかのユースケースがあるため、やや複雑です:
- モデルに対して変換を行い、それを個々のインスタンスに適用する場合。これにより、インスタンステーブルを変更することなく、すべてのインスタンスを一度に回転させるなど、効率的なアニメーションが可能になります。
- インスタンスのグループ全体を一括して変形する。
- モデル階層のインスタンス化。
これらすべてのケースに対応するため、モデルのトランスフォームは「ローカルインスタンストランスフォーム」と「グローバルインスタンストランスフォーム」の2つの部分に分割されています。概念的には、インスタンス化は次のように行われます:
- まず、モデルがローカルインスタンス変換に従って変換されます。
- 次に、インスタンステーブルのトランスフォームを適用して各インスタンスを計算します。
- 最後に、インスタンス化されたオブジェクトのグループ全体が、グローバルインスタンス変換に従って変換されます。
デフォルトでは、モデルのローカルインスタンス変換はモデルのスケールと回転で構成され、それ以外はグローバルインスタンス変換に含まれます。
これは、モデルの `instanceRoot ` プロパティを設定することで制御できます。これにより、インスタンスの座標系の原点が定義されます。最も一般的な用途は、モデルの階層構造をインスタンス化する場合です。例えば、立方体の周りを公転する球体の場合:
Model {
id: cube
instancing: someInstanceTable
source: "#Cube"
materials: DefaultMaterial { diffuseColor: "lightgray" }
Node {
Model {
source: "#Sphere"
instanceRoot: cube
instancing: cube.instancing
x: 150
materials: DefaultMaterial { diffuseColor: "gray" }
}
NumberAnimation on eulerRotation.y {
from: 0
to: 360
duration: 4000
loops: Animation.Infinite
}
}
}instanceRoot は、球体のインスタンスがあたかも立方体の構成要素であるかのように配置されるように指定するために必要です。階層内の各モデルは、依然としてinstancing プロパティを指定する必要があります。通常の場合、これらはすべて同じInstancing オブジェクトに設定されるべきです。
instanceRoot 単一のモデルをインスタンス化する際にも使用できます。例えば、中心から外れた点を中心に回転する円柱の場合:
Node {
id: parentNode
Model {
source: "#Cylinder"
instanceRoot: parentNode
instancing: anotherInstanceTable
x: 25
materials: DefaultMaterial { diffuseColor: "white" }
}
NumberAnimation on eulerRotation.y {
from: 0
to: 360
duration: 1000
loops: Animation.Infinite
}
}選択とインスタンス化
Picking は、ユーザーインターフェース操作を通じてモデルを選択できるようにする仕組みです。インスタンス化されたレンダリングでは、同じモデルの複数の表現が存在するため、選択結果にはinstance index が含まれます。インスタンス化された選択は、ベースモデルのpickable プロパティを設定することで有効になります。
© 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.