Auf dieser Seite

Qt Quick 3D - Einfaches Skinning-Beispiel

Zeigt, wie man eine einfache Skinning-Animation in „ Qt Quick 3D “ rendert.

Zwei animierte Formen, die eine Skelettverformung darstellen

In der Regel werden die meisten Skin-Animationen mit Modellierungswerkzeugen erstellt, und Quick3D unterstützt über den Balsam-Importer auch glTF-Formate sowie Qt Design Studio. Dieses Beispiel zeigt, wie die einzelnen Eigenschaften für die Skin-Animation in Quick3D verwendet werden.

Hinweis: Alle Daten in diesem Beispiel stammen aus „gfTF-Tutorial Skins“.

Erstellen Sie eine Skinning-Geometrie.

Um benutzerdefinierte Geometriedaten zu verwenden, definieren wir eine Geometrie mit Positionen, Gelenken, Gewichten und Indizes.

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)

Jede Position ist eine Scheitelpunktposition, und jeder Scheitelpunkt verfügt über 4 Gelenk-Indizes und entsprechende Gewichte.

Richten Sie die Skinned-Daten in QML ein

Positionsdaten und Indizes

Wir zeichnen 8 Dreiecke mit 10 Scheitelpunkten. Die folgende Tabelle zeigt den QML-Code und eine Visualisierung der Scheitelpunkte.

QML-CodeVisualisiert
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
]

Scheitelpunktpositionen und Geometrie

Daten zu Gelenken und Gewichten

Jeder Scheitelpunkt muss die Indizes der Gelenke angeben, die während des Skinning-Prozesses Einfluss auf ihn haben sollen. Für jeden Scheitelpunkt speichern wir diese Indizes als 4D-Vektoren (Qt begrenzt die Anzahl der Gelenke, die einen Scheitelpunkt beeinflussen dürfen, auf 4). Unsere Geometrie wird nur zwei Gelenkknoten (0 und 1) haben, aber da wir 4D-Vektoren verwenden, setzen wir die verbleibenden beiden Gelenkindizes und ihre Gewichte auf 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
]

Die entsprechenden Gewichtungswerte sind unten aufgeführt.

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
]
Skelett- und Gelenkhierarchie

Für das Skinning fügen wir dem „ Model “ eine Skelett -Eigenschaft hinzu:

skeleton: qmlskeleton
Skeleton {
    id: qmlskeleton
    Joint {
        id: joint0
        index: 0
        skeletonRoot: qmlskeleton
        Joint {
            id: joint1
            index: 1
            skeletonRoot: qmlskeleton
            eulerRotation.z: 45
        }
    }
}

Die beiden „ Joints“ sind in einer „ Skeleton “ miteinander verbunden. Wir drehen „ joint1 “ um 45 Grad um die z-Achse. Die folgenden Abbildungen zeigen, wie die Gelenke in der Geometrie platziert sind und wie das anfängliche Skelett ausgerichtet ist.

Gelenke in der GeometrieAusgangsskelett

2 Gelenke in der Geometrie

Erstes Grundgerüst

Platzieren von Modellen mit „inverseBindPoses“

Sobald ein Modell über eine gültige „ skeleton “ verfügt, muss die Ausgangsposition des Skeletts definiert werden. Dies legt die Basis für die Skelettanimation fest: Wird ein Gelenk aus seiner Ausgangsposition verschoben, bewegen sich die Scheitelpunkte des Modells entsprechend den Tabellen „ joints “ und „ weights “. Die Geometrie jedes Knotens wird auf besondere Weise festgelegt: „ Model.inverseBindPoses “ wird auf die Inverse der Matrix gesetzt, die das Gelenk in seine Ausgangsposition transformieren würde. Um es in die Mitte zu verschieben, setzen wir einfach für beide Gelenke dieselbe Transformation: eine Matrix, die um -0,5 entlang der x-Achse und um -1,0 entlang der y-Achse verschiebt.

QML-CodeAusgangspositionErgebnis
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)
]

Ausgangsposition

Transformiert mit InversebindPoses

Animieren mit Gelenkknoten

Nachdem wir nun ein Skinned-Objekt vorbereitet haben, können wir es animieren, indem wir die Eigenschaften des „ Joint“ ändern, insbesondere „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
        }
    }
}

Ein umfassenderer Ansatz zum Skinning

Das Skelett ist eine Ressource, doch seine Hierarchie und Position werden für die Transformation des Modells verwendet.

Anstelle eines „ Skeleton “-Knotens können wir den Ressourcentyp „ Skin “ verwenden. Da der Typ „ Skin “ kein räumlicher Knoten in der Szene ist, hat seine Position keinen Einfluss auf das Modell. Ein minimal funktionsfähiger „Skin“-Knoten besteht normalerweise aus einer Knotenliste, Gelenken und optionalen inversen Bindungsmatrizen („inverseBindPoses“).

Mit dem Element „ Skin “ lässt sich das vorherige Beispiel wie folgt schreiben:

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)
    ]
}

Aus dem Codeausschnitt geht hervor, dass der „ Skin “ nur zwei Listen enthält, nämlich „joints“ und „inverseBindPoses“. Dies unterscheidet sich vom Ansatz „ Skeleton “, da hier keine eigene Hierarchie vorhanden ist und stattdessen die Hierarchie der vorhandenen Knoten genutzt wird.

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

Beispielprojekt @ 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.