Qt Quick 3D - 간단한 스키닝 예제
Qt Quick 3D 에서 간단한 스키닝 애니메이션을 렌더링하는 방법을 보여줍니다.

일반적으로 대부분의 스킨 애니메이션은 모델링 툴을 통해 디자인되며, Quick3D는 Balsam 임포터를 통해 glTF 형식도 지원합니다. Qt Design Studio이를 통해 glTF 형식도 지원합니다. 이 예제는 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는 한 꼭짓점에 영향을 미칠 수 있는 조인트의 수를 4개로 제한합니다). 이 지오메트리에는 두 개의 조인트 노드(0과 1)만 있지만, 4차원 벡터를 사용하기 때문에 나머지 두 조인트 인덱스와 해당 가중치를 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 코드 | 초기 위치 | 결과 |
|---|---|---|
|
|
|
조인트 노드를 사용한 애니메이션
스킨이 적용된 오브젝트를 준비했으므로, 이제 Joint의 속성, 특히 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`라는 두 개의 목록만 포함되어 있습니다. 이는 ` 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.




