Qt Quick 3D - Rendu instancié personnalisé
Démonstration de l'instanciation avec des matériaux personnalisés et une table d'instances en C++.

Cet exemple montre comment créer des données d'instance par programmation en C++, et comment utiliser des matériaux personnalisés avec le rendu instancié.
Table d’instanciation personnalisée
Nous définissons notre table comme une sous-classe de ` QQuick3DInstancing ` et ajoutons quelques propriétés afin de pouvoir la contrôler depuis 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)La fonction virtuelle ` getInstanceBuffer ` est réimplémentée pour renvoyer les données d'instanciation :
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;
}Matériau personnalisé
Nous utilisons un matériau personnalisé ombré, ce qui signifie que Qt nous fournit l’implémentation de base et que nous nous contentons de spécifier la logique supplémentaire.
La seule personnalisation dont nous avons besoin pour le shader de sommets consiste à transmettre des informations au shader de fragments. Par défaut, Qt ne fournit que les données d’instance au shader de sommets ; nous les transmettons donc sous la forme ` vCustomData`. Nous calculons également la position globale du sommet et la rendons disponible sous la forme ` 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;
}Le shader de fragments réalise une animation simple de vagues pour les surfaces d’eau. Tout le reste bénéficie d’un dégradé radial subtil. La différence est déterminée par le premier élément des données personnalisées.
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);
}Utilisation de la table et du matériau personnalisés dans QML
Nous créons un matériau personnalisé à l'aide des shaders que nous avons créés précédemment, puis ajoutons une nouvelle propriété uTime. Cette propriété est automatiquement mappée à l'uniform correspondant dans le shader de fragment.
CustomMaterial {
id: cubeMaterial
property real uTime: frametimer.elapsedTime
FrameAnimation {
id: frametimer
running: true
}
vertexShader: "cubeMaterial.vert"
fragmentShader: "cubeMaterial.frag"
}Enfin, nous créons notre modèle et lui appliquons le matériau personnalisé ainsi que la table d’instances :
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 ]
}Notez que nous ne créons qu’un seul cube : tout le travail est effectué par le 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.