Qt Quick 3D - Exemple simple de skinning
Ce guide montre comment générer une animation de skinning simple dans Qt Quick 3D.

En général, la plupart des animations de skinning sont conçues à l'aide d'outils de modélisation, et Quick3D prend également en charge les formats glTF via l'importateur Balsam et Qt Design Studio. Cet exemple montre comment chaque propriété est utilisée pour l'animation de skin dans Quick3D.
Remarque : toutes les données de cet exemple proviennent de « gfTF-Tutorial Skins ».
Créer une géométrie de skinning.
Pour utiliser des données géométriques personnalisées, nous allons définir une géométrie comportant des positions, des articulations, des poids et des indices.
Q_OBJECT
QML_NAMED_ELEMENT(SkinGeometry)
Q_PROPERTY(QList<QVector3D> positions READ positions WRITE setPositions NOTIFY positionsChanged)
Q_PROPERTY(QList<qint32> joints READ joints WRITE setJoints NOTIFY jointsChanged)
Q_PROPERTY(QList<float> weights READ weights WRITE setWeights NOTIFY weightsChanged)
Q_PROPERTY(QList<quint32> indexes READ indexes WRITE setIndexes NOTIFY indexesChanged)Chaque position correspond à un sommet, et chaque sommet possède 4 indices d’articulations ainsi que les poids correspondants.
Configurer les données de skinning en QML
Données de position et index
Nous allons dessiner 8 triangles comportant 10 sommets. Le tableau ci-dessous présente le code QML et une visualisation des sommets.
| Code QML | Visualisation |
|---|---|
|
|
Données relatives aux articulations et aux poids
Chaque sommet doit spécifier les indices des articulations qui doivent l'influencer pendant le processus de skinning. Pour chaque sommet, nous stockons ces indices sous forme de vecteurs 4D (Qt limite à 4 le nombre d'articulations pouvant influencer un sommet). Notre géométrie ne comportera que deux nœuds d'articulation (0 et 1), mais comme nous utilisons des vecteurs 4D, nous définissons les deux indices d'articulation restants et leurs poids à 0.
joints: [
0, 1, 0, 0, // vertex 0
0, 1, 0, 0, // vertex 1
0, 1, 0, 0, // vertex 2
0, 1, 0, 0, // vertex 3
0, 1, 0, 0, // vertex 4
0, 1, 0, 0, // vertex 5
0, 1, 0, 0, // vertex 6
0, 1, 0, 0, // vertex 7
0, 1, 0, 0, // vertex 8
0, 1, 0, 0 // vertex 9
]Les valeurs de poids correspondantes sont les suivantes.
weights: [
1.00, 0.00, 0.0, 0.0, // vertex 0
1.00, 0.00, 0.0, 0.0, // vertex 1
0.75, 0.25, 0.0, 0.0, // vertex 2
0.75, 0.25, 0.0, 0.0, // vertex 3
0.50, 0.50, 0.0, 0.0, // vertex 4
0.50, 0.50, 0.0, 0.0, // vertex 5
0.25, 0.75, 0.0, 0.0, // vertex 6
0.25, 0.75, 0.0, 0.0, // vertex 7
0.00, 1.00, 0.0, 0.0, // vertex 8
0.00, 1.00, 0.0, 0.0 // vertex 9
]Hiérarchie du squelette et des articulations
Pour le skinning, nous ajoutons une propriété « skeleton » à l’ Model:
skeleton: qmlskeleton
Skeleton {
id: qmlskeleton
Joint {
id: joint0
index: 0
skeletonRoot: qmlskeleton
Joint {
id: joint1
index: 1
skeletonRoot: qmlskeleton
eulerRotation.z: 45
}
}
}Les deux objets « Joint» sont reliés dans une « Skeleton ». Nous allons faire pivoter « joint1 » de 45 degrés autour de l’axe z. Les images ci-dessous montrent comment les articulations sont placées dans la géométrie et comment le squelette initial est orienté.
| Articulations dans la géométrie | Squelette initial |
|---|---|
|
|
Placement des modèles à l’aide de inverseBindPoses
Une fois qu’un modèle dispose d’une matrice de position ( skeleton) valide, il est nécessaire de définir la pose initiale du squelette. Cela définit la base de référence pour l’animation squelettique : déplacer une articulation depuis sa position initiale entraîne le déplacement des sommets du modèle conformément aux tables « joints » et « weights ». La géométrie de chaque nœud est spécifiée d’une manière particulière : Model.inverseBindPoses est défini comme l’inverse de la matrice qui transformerait l’articulation vers sa position initiale. Pour le déplacer vers le centre, il suffit de définir la même transformation pour les deux articulations : une matrice qui effectue une translation de -0,5 le long de l’axe x et de -1,0 le long de l’axe y.
| Code QML | Position initiale | Résultat |
|---|---|---|
|
|
|
Animation avec des nœuds « Joint »
Maintenant que nous avons préparé un objet skinné, nous pouvons l'animer en modifiant les propriétés de l'Joint, notamment eulerRotation.
Timeline {
id: timeline0
startFrame: 0
endFrame: 1000
currentFrame: 0
enabled: true
animations: [
TimelineAnimation {
duration: 5000
from: 0
to: 1000
running: true
}
]
KeyframeGroup {
target: joint1
property: "eulerRotation.z"
Keyframe {
frame: 0
value: 0
}
Keyframe {
frame: 250
value: 90
}
Keyframe {
frame: 750
value: -90
}
Keyframe {
frame: 1000
value: 0
}
}
}Une approche plus complète du skinning
Le squelette est une ressource, mais sa hiérarchie et sa position sont utilisées pour la transformation du modèle.
Au lieu d’un nœud « Skeleton », nous pouvons utiliser le type de ressource « Skin ». Comme le type « Skin » n’est pas un nœud spatial dans la scène, sa position n’affectera pas le modèle. Un nœud « Skin » fonctionnel minimal se compose généralement d’une liste de nœuds, de joints et, en option, de matrices de liaison inverses (« inverseBindPoses »).
En utilisant l’élément « Skin », l’exemple précédent peut s’écrire ainsi :
skin: Skin {
id: skin0
joints: [
joint0,
joint1
]
inverseBindPoses: [
Qt.matrix4x4(1, 0, 0, -0.5,
0, 1, 0, -1,
0, 0, 1, 0,
0, 0, 0, 1),
Qt.matrix4x4(1, 0, 0, -0.5,
0, 1, 0, -1,
0, 0, 1, 0,
0, 0, 0, 1)
]
}D'après cet extrait de code, on constate que l'Skin ne comporte que deux listes : une liste de joints et une liste inverseBindPoses. Cette approche diffère de celle de Skeleton, car elle ne comporte aucune hiérarchie et utilise simplement la hiérarchie des nœuds existants.
© 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.




