Qt Quick 3D - 简单的蒙皮示例
演示如何在Qt Quick 3D 中渲染简单的蒙皮动画。

通常,大多数皮肤动画都是通过建模工具设计的,Quick3D 还通过Balsam 导入器和 Qt Design Studio。本示例展示了在 Quick3D 中皮肤动画中各项属性的具体用法。
注意: 本示例中的所有数据均 来自gfTF-Tutorial Skins。
创建一个骨骼绑定几何体。
要使用自定义几何体数据,我们将定义一个包含位置、关节、权重和索引的几何体。
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)每个位置都是一个顶点位置,每个顶点都有 4 个关节索引和相应的权重。
在 QML 中设置蒙皮数据
位置数据和索引
我们将绘制8个三角形,共包含10个顶点。下表展示了QML代码以及顶点的可视化效果。
| QML 代码 | 可视化效果 |
|---|---|
|
|
关节和权重数据
每个顶点都需要指定在蒙皮过程中对其产生影响的关节索引。对于每个顶点,我们将这些索引存储为 4D 向量(Qt 将可影响一个顶点的关节数量限制为 4 个)。 我们的几何体只有两个关节节点(0 和 1),但由于我们使用的是 4D 向量,因此将剩余的两个关节索引及其权重设置为 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
]相应的权重值如下所示。
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
]骨骼与关节层级结构
为了进行蒙皮,我们在Model 上添加了一个骨骼属性:
skeleton: qmlskeleton
Skeleton {
id: qmlskeleton
Joint {
id: joint0
index: 0
skeletonRoot: qmlskeleton
Joint {
id: joint1
index: 1
skeletonRoot: qmlskeleton
eulerRotation.z: 45
}
}
}两个Joint通过Skeleton 连接。我们将joint1 绕z轴旋转45度。下图展示了关节在几何体中的布置方式以及初始骨骼的朝向。
| 几何体中的关节 | 初始骨架 |
|---|---|
|
|
使用 inverseBindPoses 放置模型
当模型拥有有效的skeleton 后,必须定义骨骼的初始姿态。这将确定骨骼动画的基准:将关节从其初始位置移动,会根据joints 和weights 表使模型的顶点随之移动。 每个节点的几何形状以一种特殊的方式指定:Model.inverseBindPoses 被设置为将关节变换到其初始位置所需的矩阵的逆矩阵。 为了将其移动到中心,我们只需为两个关节设置相同的变换:一个沿 x 轴平移 -0.5、沿 y 轴平移 -1.0 的矩阵。
| QML 代码 | 初始位置 | 结果 |
|---|---|---|
|
|
|
使用关节节点进行动画制作
现在我们已经准备好了一个带骨骼绑定(skinned)的对象,可以通过更改Joints的属性(特别是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
}
}
}一种更完整的骨骼绑定方法
骨骼是一种资源,但其层次结构和位置用于模型的变换。
除了Skeleton 节点外,我们还可以使用Skin 资源类型。由于Skin 类型在场景中并非空间节点,因此其位置不会影响模型。一个最简的可工作Skin节点通常由节点列表、关节以及可选的逆绑定矩阵inverseBindPoses组成。
使用Skin 项,前面的示例可以这样编写:
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)
]
}从代码片段中可以看出,Skin 仅包含两个列表:joints 和 inverseBindPoses,这与Skeleton 的实现方式不同,因为它不包含任何层级结构,而是直接利用现有节点的层级结构。
© 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.




