Qt Quick 3D - カスタムインスタンスレンダリング
カスタムマテリアルとC++のインスタンステーブルを使用したインスタンス化のデモです。

このサンプルでは、C++でプログラム的にインスタンスデータを作成する方法と、インスタンス化レンダリングでカスタムマテリアルを使用する方法を示します。
カスタムインスタンス化テーブル
テーブルをQQuick3DInstancing のサブクラスとして定義し、QMLから制御できるようにいくつかのプロパティを追加します:
class CppInstanceTable : public QQuick3DInstancing
{
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(int gridSize READ gridSize WRITE setGridSize NOTIFY gridSizeChanged)
Q_PROPERTY(float gridSpacing READ gridSpacing WRITE setGridSpacing NOTIFY gridSpacingChanged)
Q_PROPERTY(int randomSeed READ randomSeed WRITE setRandomSeed NOTIFY randomSeedChanged)仮想関数 `getInstanceBuffer ` を再実装し、インスタンスデータを返すようにします:
QByteArray CppInstanceTable::getInstanceBuffer(int *instanceCount)
{
if (m_dirty) {
BlockTable blocks(m_gridSize, m_randomSeed);
m_instanceData.resize(0);
auto idxToPos = [this](int i) -> float { return m_gridSpacing * (i - m_gridSize / 2); };
int instanceNumber = 0;
for (int i = 0; i < m_gridSize; ++i) {
float xPos = idxToPos(i);
for (int j = 0; j < m_gridSize; ++j) {
float zPos = idxToPos(j);
int lowest = blocks.lowestVisible(i, j);
int highest = blocks.highestBlock(i, j);
for (int k = lowest; k <= highest; ++k) {
float yPos = idxToPos(k);
QColor color = blocks.getBlockColor(i, j, k);
float waterAnimation = blocks.isWaterSurface(i, j, k) ? 1.0 : 0.0;
auto entry = calculateTableEntry({ xPos, yPos, zPos }, { 1.0, 1.0, 1.0 }, {}, color, { waterAnimation, 0, 0, 0 });
m_instanceData.append(reinterpret_cast<const char *>(&entry), sizeof(entry));
instanceNumber++;
}
}
}
m_instanceCount = instanceNumber;
m_dirty = false;
}
if (instanceCount)
*instanceCount = m_instanceCount;
return m_instanceData;
}カスタムマテリアル
シェーディングされたカスタムマテリアルを使用します。つまり、Qtが基本実装を提供し、追加のロジックを指定するだけです。
頂点シェーダーで必要な唯一のカスタマイズは、フラグメントシェーダーへの情報渡しです。デフォルトでは、Qtはインスタンスデータのみを頂点シェーダーに提供するため、これをvCustomData として渡します。また、頂点のグローバル位置を計算し、vGlobalPosition として利用可能にします。
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
VARYING vec4 vCustomData;
VARYING vec3 vGlobalPosition;
void MAIN()
{
vCustomData = INSTANCE_DATA;
// MODEL_MATRIX does not exist when instancing
vec4 pos = INSTANCE_MODEL_MATRIX * vec4(VERTEX, 1.0);
vGlobalPosition = pos.xyz;
}フラグメントシェーダーは、水面に対して単純な波のアニメーションを実行します。それ以外の部分には、微妙な放射状のグラデーションが適用されます。この違いは、カスタムデータの最初の要素によって決定されます。
VARYING vec4 vCustomData;
VARYING vec3 vGlobalPosition;
void MAIN()
{
METALNESS = 0.0;
ROUGHNESS = 1.0;
FRESNEL_POWER = 5.0;
float c;
if (vCustomData.x > 0)
c = 1.0 - (1.0 + sin(sqrt(vGlobalPosition.x*vGlobalPosition.x + vGlobalPosition.z*vGlobalPosition.z) - uTime/200.0)) * 0.2;
else
c = 1.0 - 0.25 * (UV0.x*UV0.x + UV0.y*UV0.y);
BASE_COLOR = vec4(c, c, c, 1.0);
}QMLでのカスタムテーブルとマテリアルの使用
先に作成したシェーダーを使用してカスタムマテリアルを作成し、新しいプロパティ `uTime` を追加します。このプロパティは、フラグメントシェーダー内の対応するユニフォームに自動的にマッピングされます。
CustomMaterial {
id: cubeMaterial
property real uTime: frametimer.elapsedTime
FrameAnimation {
id: frametimer
running: true
}
vertexShader: "cubeMaterial.vert"
fragmentShader: "cubeMaterial.frag"
}最後に、モデルを作成し、カスタムマテリアルとインスタンステーブルを適用します:
Model {
id: instancedCube
property real cubeSize: 15
scale: Qt.vector3d(cubeSize/100, cubeSize/100, cubeSize/100)
source: "#Cube"
instancing: CppInstanceTable {
gridSize: 65
gridSpacing: instancedCube.cubeSize
randomSeed: 1522562186
}
materials: [ cubeMaterial ]
}ここで注意すべき点は、作成するのは単一のキューブだけだということです。すべての処理はGPUによって行われます。
© 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.