Sur cette page

Qt Quick 3D - Exemple simple de skinning

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

Deux formes animées illustrant une déformation squelettique

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 QMLVisualisation
positions: [
    Qt.vector3d(0.0, 0.0, 0.0), // vertex 0
    Qt.vector3d(1.0, 0.0, 0.0), // vertex 1
    Qt.vector3d(0.0, 0.5, 0.0), // vertex 2
    Qt.vector3d(1.0, 0.5, 0.0), // vertex 3
    Qt.vector3d(0.0, 1.0, 0.0), // vertex 4
    Qt.vector3d(1.0, 1.0, 0.0), // vertex 5
    Qt.vector3d(0.0, 1.5, 0.0), // vertex 6
    Qt.vector3d(1.0, 1.5, 0.0), // vertex 7
    Qt.vector3d(0.0, 2.0, 0.0), // vertex 8
    Qt.vector3d(1.0, 2.0, 0.0)  // vertex 9
]
indexes: [
    0, 1, 3, // triangle 0
    0, 3, 2, // triangle 1
    2, 3, 5, // triangle 2
    2, 5, 4, // triangle 3
    4, 5, 7, // triangle 4
    4, 7, 6, // triangle 5
    6, 7, 9, // triangle 6
    6, 9, 8  // triangle 7
]

Positions des sommets et géométrie

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étrieSquelette initial

2 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 QMLPosition initialeRésultat
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)
]

Position initiale

Transformé par InversebindPoses

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.

Node {
    id: joint0
    Node {
        id: joint1
        eulerRotation.z: 45
    }
}

Exemple de projet sur code.qt.io

© 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.