Qt Quick 3D - Ejemplo de skinning simple
Demuestra cómo renderizar una animación simple de skinning en Qt Quick 3D.

Generalmente la mayoría de las animaciones de skin serán diseñadas por herramientas de modelado, y Quick3D también soporta formatos glTF a través del importador Balsam y Qt Design Studio. Este ejemplo muestra cómo se utiliza cada propiedad para la animación de skin en Quick3D.
Nota: Todos los datos de este ejemplo provienen de gfTF-Tutorial Skins.
Haga una geometría de skinning.
Para utilizar datos de geometría personalizados, definiremos una geometría que tenga posiciones, articulaciones, pesos e índices.
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)
Cada posición es una posición de vértice y cada vértice tiene 4 índices de articulaciones y sus pesos correspondientes.
Configurar datos personalizados en QML
Datos de posición e índices
Dibujaremos 8 triángulos con 10 vértices. La siguiente tabla muestra el código QML y una visualización de los vértices.
| Código QML | Visualización |
|---|---|
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 ] |
|
Datos de posición y pesos
Cada vértice necesita especificar los índices de las articulaciones que deben influir sobre él durante el proceso de despellejado. Para cada vértice almacenamos estos índices como vectores 4D (Qt limita el número de articulaciones que pueden influir en un vértice a 4). Nuestra geometría tendrá sólo dos nodos de articulación (0 y 1), pero como usamos vectores 4D establecemos los dos índices de articulación restantes y sus pesos a 0. Los valores de peso correspondientes son los siguientes
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 ]
Los valores de peso correspondientes son los siguientes.
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 ]
Esqueleto y jerarquía de articulaciones
Para el skinning, añadimos una propiedad de esqueleto a Model:
skeleton: qmlskeleton Skeleton { id: qmlskeleton Joint { id: joint0 index: 0 skeletonRoot: qmlskeleton Joint { id: joint1 index: 1 skeletonRoot: qmlskeleton eulerRotation.z: 45 } } }
Los dos Joints están conectados en un Skeleton. Rotaremos joint1 45 grados alrededor del eje z. Las imágenes siguientes muestran cómo se colocan las articulaciones en la geometría y cómo se orienta el esqueleto inicial.
| Articulaciones en la geometría | Esqueleto inicial |
|---|---|
|
|
Colocación de modelos mediante inverseBindPoses
Una vez que un modelo tiene un skeleton válido, es necesario definir la pose inicial del esqueleto. Esto define la línea base para la animación del esqueleto: mover una articulación desde su posición inicial hace que los vértices del modelo se muevan de acuerdo con las tablas joints y weights. La geometría de cada nodo se especifica de una manera peculiar: Model.inverseBindPoses se establece a la inversa de la matriz que transformaría la articulación a su posición inicial. Para moverla al centro, simplemente estableceremos la misma transformación para ambas articulaciones: una matriz que traslada -0.5 a lo largo del eje x y -1.0 a lo largo del eje y.
| Código QML | Posición inicial | Resultado |
|---|---|---|
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) ] |
|
|
Animar con nodos Joint
Ahora que hemos preparado un objeto con skin, podemos animarlo cambiando las propiedades de Joint, específicamente 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 } } }
Una aproximación más completa al skinning
El esqueleto es un recurso, pero su jerarquía y posición se utiliza para la transformación del modelo.
En lugar de un nodo Skeleton, podemos utilizar el tipo de recurso Skin. Dado que el tipo Skin no es un nodo espacial en la escena, su posición no afectará al modelo. Un nodo Skin de trabajo mínimo consistirá normalmente en una lista de nodos, articulaciones y una matriz de bind inversa opcional, inverseBindPoses.
Usando el elemento Skin el ejemplo anterior puede escribirse así:
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) ] }
Del fragmento de código podemos ver que el Skin sólo tiene dos listas, una joints y una inverseBindPoses, lo que difiere del enfoque Skeleton, ya que no tiene ninguna jerarquía y sólo utiliza la jerarquía del nodo existente.
© 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.




