Qt Quick 3D - 簡単なスキニングの例
Qt Quick 3Dで簡単なスキニングアニメーションをレンダリングする方法を解説します。

一般的に、ほとんどのスキニングアニメーションはモデリングツールで設計されますが、Quick3DではBalsamインポーターを通じてglTF形式もサポートしており、 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でスキニングデータを設定する
位置データとインデックス
10個の頂点を持つ8つの三角形を描画します。以下の表は、QMLコードと頂点の可視化を示しています。
| QMLコード | 可視化 |
|---|---|
|
|
ジョイントとウェイトのデータ
各頂点については、スキニング処理中にその頂点に影響を与えるべきジョイントのインデックスを指定する必要があります。各頂点について、これらのインデックスを4次元ベクトルとして格納します(Qtでは、1つの頂点に影響を与えるジョイントの数を4つまでに制限しています)。 このジオメトリにはジョイントノードが2つ(0と1)しかありませんが、4次元ベクトルを使用するため、残りの2つのジョイントインデックスとその重みを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
}
}
}2つのJointは、Skeleton で接続されています。joint1 をz軸を中心に45度回転させます。以下の画像は、ジオメトリ内でのジョイントの配置と、初期のスケルトンの向きを示しています。
| ジオメトリ内のジョイント | 初期スケルトン |
|---|---|
|
|
inverseBindPosesを使用したモデルの配置
モデルに有効なskeleton が設定されると、スケルトンの初期ポーズを定義する必要があります。これにより、スケルトンアニメーションの基準が確立されます。ジョイントを初期位置から移動させると、joints およびweights テーブルに従ってモデルの頂点が移動します。 各ノードのジオメトリは、独特な方法で指定されます。Model.inverseBindPoses には、関節を初期位置に変換する行列の逆行列が設定されます。 中心に移動させるには、両方のジョイントに同じ変換を設定するだけです。つまり、x 軸に沿って -0.5、y 軸に沿って -1.0 だけ平行移動させる行列を設定します。
| QML コード | 初期位置 | 結果 |
|---|---|---|
|
|
|
Joint ノードを使ったアニメーション
スキニングされたオブジェクトの準備ができたので、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 タイプはシーン内の空間ノードではないため、その位置はモデルに影響を与えません。最低限機能するスキンノードは、通常、ノードリスト、ジョイント、およびオプションの逆バインド行列(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の2つのリストしか含まれていないことがわかります。これは、階層構造を持たず、既存のノードの階層構造をそのまま利用する点で、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.




