Qt Quick 3D - Exemple de géométrie personnalisée
Illustre la fourniture de données de sommets personnalisées à partir de C++ et de QML.

Cet exemple utilise les méthodes QQuick3DGeometry et the geometry property de l'objet Model pour rendre un maillage dont les coordonnées de sommets, les normales et les coordonnées de texture sont spécifiées depuis C++ et QML, au lieu d'utiliser un élément pré-calculé.
De plus, l’utilisation de ` GridGeometry ` est également illustrée. ` GridGeometry ` est une implémentation intégrée de ` QQuick3DGeometry ` qui fournit un maillage avec des primitives de ligne adaptées à l’affichage d’une grille.
Dans cet exemple, nous nous concentrerons sur le code qui fournit la géométrie personnalisée ; examinons donc tout d’abord le fichier d’en-tête C++ de ` ExampleTriangleGeometry ` :
class ExampleTriangleGeometry : public QQuick3DGeometry
{
Q_OBJECT
QML_NAMED_ELEMENT(ExampleTriangleGeometry)
Q_PROPERTY(bool normals READ normals WRITE setNormals NOTIFY normalsChanged)
Q_PROPERTY(float normalXY READ normalXY WRITE setNormalXY NOTIFY normalXYChanged)
Q_PROPERTY(bool uv READ uv WRITE setUV NOTIFY uvChanged)
Q_PROPERTY(float uvAdjust READ uvAdjust WRITE setUVAdjust NOTIFY uvAdjustChanged)
public:
ExampleTriangleGeometry();
bool normals() const { return m_hasNormals; }
void setNormals(bool enable);
float normalXY() const { return m_normalXY; }
void setNormalXY(float xy);
bool uv() const { return m_hasUV; }
void setUV(bool enable);
float uvAdjust() const { return m_uvAdjust; }
void setUVAdjust(float f);
signals:
void normalsChanged();
void normalXYChanged();
void uvChanged();
void uvAdjustChanged();
private:
void updateData();
bool m_hasNormals = false;
float m_normalXY = 0.0f;
bool m_hasUV = false;
float m_uvAdjust = 0.0f;
};Le point le plus important à noter est que notre classe ` ExampleTriangleGeometry ` hérite de ` QQuick3DGeometry ` et que nous appelons la macro ` QML_NAMED_ELEMENT(ExampleTriangleGeometry) `, ce qui rend notre classe accessible en QML. Quelques propriétés sont également définies via la macro ` Q_PROPERTY ` et sont automatiquement exposées dans notre objet QML. Examinons maintenant le modèle QML :
Model {
id: triangleModel
visible: false
scale: Qt.vector3d(100, 100, 100)
geometry: ExampleTriangleGeometry {
normals: cbNorm.checked
normalXY: sliderNorm.value
uv: cbUV.checked
uvAdjust: sliderUV.value
}
materials: [
PrincipledMaterial {
Texture {
id: baseColorMap
source: "qt_logo_rect.png"
}
cullMode: PrincipledMaterial.NoCulling
baseColorMap: cbTexture.checked ? baseColorMap : null
specularAmount: 0.5
}
]
}Notez que nous spécifions la propriété ` geometry ` pour utiliser notre classe ` ExampleTriangleGeometry `, avec les propriétés pertinentes indiquées. C’est tout ce qui est nécessaire côté QML pour utiliser une géométrie personnalisée.
Examinons maintenant l’autre partie importante du code C++, à savoir la méthode ` updateData() `. Cette méthode crée et télécharge les données de notre géométrie personnalisée chaque fois qu’une classe ` ExampleTriangleGeometry ` est créée ou que l’une de ses propriétés QML est mise à jour.
void ExampleTriangleGeometry::updateData()
{
clear();
int stride = 3 * sizeof(float);
if (m_hasNormals)
stride += 3 * sizeof(float);
if (m_hasUV)
stride += 2 * sizeof(float);
QByteArray vertexData(3 * stride, Qt::Initialization::Uninitialized);
float *p = reinterpret_cast<float *>(vertexData.data());
// a triangle, front face = counter-clockwise
*p++ = -1.0f; *p++ = -1.0f; *p++ = 0.0f;
if (m_hasNormals) {
*p++ = m_normalXY; *p++ = m_normalXY; *p++ = 1.0f;
}
if (m_hasUV) {
*p++ = 0.0f + m_uvAdjust; *p++ = 0.0f + m_uvAdjust;
}
*p++ = 1.0f; *p++ = -1.0f; *p++ = 0.0f;
if (m_hasNormals) {
*p++ = m_normalXY; *p++ = m_normalXY; *p++ = 1.0f;
}
if (m_hasUV) {
*p++ = 1.0f - m_uvAdjust; *p++ = 0.0f + m_uvAdjust;
}
*p++ = 0.0f; *p++ = 1.0f; *p++ = 0.0f;
if (m_hasNormals) {
*p++ = m_normalXY; *p++ = m_normalXY; *p++ = 1.0f;
}
if (m_hasUV) {
*p++ = 1.0f - m_uvAdjust; *p++ = 1.0f - m_uvAdjust;
}
setVertexData(vertexData);
setStride(stride);
setBounds(QVector3D(-1.0f, -1.0f, 0.0f), QVector3D(+1.0f, +1.0f, 0.0f));
setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
0,
QQuick3DGeometry::Attribute::F32Type);
if (m_hasNormals) {
addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
3 * sizeof(float),
QQuick3DGeometry::Attribute::F32Type);
}
if (m_hasUV) {
addAttribute(QQuick3DGeometry::Attribute::TexCoordSemantic,
m_hasNormals ? 6 * sizeof(float) : 3 * sizeof(float),
QQuick3DGeometry::Attribute::F32Type);
}
}La méthode commence par appeler ` clear() ` afin d’effacer toutes les données précédemment chargées. Elle calcule ensuite le pas pour les sommets, en tenant compte de la présence de normales et de coordonnées UV. Un tableau d’octets est ensuite créé pour contenir le tampon de sommets, qui est ensuite rempli avec les sommets d’un triangle unique dont les sommets sont situés en (-1, -1, 0), (1, -1, 0) et (0, 1, 0).
Les données de sommets sont ensuite chargées et le pas est défini en appelant ` setVertexData() ` et ` setStride()`. Les limites de la géométrie sont définies en appelant ` setBounds`. Bien que cela ne soit pas utilisé dans cet exemple, la définition des limites est nécessaire au bon fonctionnement des ombres. Ensuite, le type de primitive est défini en appelant setPrimitiveType(). Enfin, nous spécifions la manière dont les attributs de position, de normale et de coordonnées UV sont organisés en mémoire dans le tampon précédemment chargé, en appelant addAttribute() pour chaque attribut.
© 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.