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 ] }
キューブは1つしか作 成していないことに注意してください:力仕事はすべて GPU が行います。
© 2025 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.