1// Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#include "qblendedclipanimator.h"
4#include "qblendedclipanimator_p.h"
5#include <Qt3DAnimation/qabstractclipblendnode.h>
6#include <Qt3DAnimation/qchannelmapper.h>
7#include <Qt3DAnimation/qclock.h>
8
9QT_BEGIN_NAMESPACE
10
11namespace Qt3DAnimation {
12
13QBlendedClipAnimatorPrivate::QBlendedClipAnimatorPrivate()
14 : Qt3DAnimation::QAbstractClipAnimatorPrivate()
15 , m_blendTreeRoot(nullptr)
16{
17}
18
19/*!
20 \qmltype BlendedClipAnimator
21 \instantiates Qt3DAnimation::QBlendedClipAnimator
22 \inqmlmodule Qt3D.Animation
23 \inherits AbstractClipAnimator
24 \since 5.9
25
26 \brief BlendedClipAnimator is a component providing animation playback capabilities of a tree
27 of blend nodes.
28
29 An instance of BlendedClipAnimator can be aggregated by an Entity to add the ability to play
30 back animation clips and to apply the calculated animation values to properties of QObjects.
31
32 Whereas a ClipAnimator gets its animation data from a single animation clip,
33 BlendedClipAnimator can blend together multiple clips. The animation data is obtained by
34 evaluating a so called \e {blend tree}. A blend tree is a hierarchical tree structure where the
35 leaf nodes are value nodes that encapsulate an animation clip (AbstractAnimationClip); and the
36 internal nodes represent blending operations that operate on the nodes pointed to by their
37 operand properties.
38
39 To associate a blend tree with a BlendedClipAnimator, set the animator's blendTree property to
40 point at the root node of your blend tree:
41
42 \badcode
43 BlendedClipAnimator {
44 blendTree: AdditiveClipBlend {
45 ....
46 }
47 }
48 \endcode
49
50 A blend tree can be constructed from the following node types:
51
52 \note The blend node tree should only be edited when the animator is not running.
53
54 \list
55 \li Qt3D.Animation.ClipBlendValue
56 \li Qt3D.Animation.LerpClipBlend
57 \li Qt3D.Animation.AdditiveClipBlend
58 \endlist
59
60 Additional node types will be added over time.
61
62 As an example consider the following blend tree:
63
64 \badcode
65 Clip0----
66 |
67 Lerp Node----
68 | |
69 Clip1---- Additive Node
70 |
71 Clip2----
72 \endcode
73
74 This can be created and used as follows:
75
76 \badcode
77 BlendedClipAnimator {
78 blendTree: AdditiveClipBlend {
79 baseClip: LerpClipBlend {
80 startClip: ClipBlendValue {
81 clip: AnimationClipLoader { source: "walk.json" }
82 }
83
84 endClip: ClipBlendValue {
85 clip: AnimationClipLoader { source: "run.json" }
86 }
87 }
88
89 additiveClip: ClipBlendValue {
90 clip: AnimationClipLoader { source: "wave-arm.json" }
91 }
92 }
93
94 channelMapper: ChannelMapper {...}
95 running: true
96 }
97 \endcode
98
99 By authoring a set of animation clips and blending between them dynamically at runtime with a
100 blend tree, we open up a huge set of possible resulting animations. As some simple examples of
101 the above blend tree, where alpha is the additive factor and beta is the lerp blend factor we
102 can get a 2D continuum of possible animations:
103
104 \badcode
105 (alpha = 0, beta = 1) Running, No arm waving --- (alpha = 1, beta = 1) Running, Arm waving
106 | |
107 | |
108 | |
109 (alpha = 0, beta = 0) Walking, No arm waving --- (alpha = 0, beta = 1) Running, No arm waving
110 \endcode
111
112 More complex blend trees offer even more flexibility for combining your animation clips. Note
113 that the values used to control the blend tree (alpha and beta above) are simple properties on
114 the blend nodes. This means, that these properties themselves can also be controlled by
115 the animation framework.
116*/
117
118/*!
119 \class Qt3DAnimation::QBlendedClipAnimator
120 \inherits Qt3DAnimation::QAbstractClipAnimator
121
122 \inmodule Qt3DAnimation
123 \since 5.9
124
125 \brief QBlendedClipAnimator is a component providing animation playback capabilities of a tree
126 of blend nodes.
127
128 An instance of QBlendedClipAnimator can be aggregated by a QEntity to add the ability to play
129 back animation clips and to apply the calculated animation values to properties of QObjects.
130
131 Whereas a QClipAnimator gets its animation data from a single animation clip,
132 QBlendedClipAnimator can blend together multiple clips. The animation data is obtained by
133 evaluating a so called \e {blend tree}. A blend tree is a hierarchical tree structure where the
134 leaf nodes are value nodes that encapsulate an animation clip (QAbstractAnimationClip); and the
135 internal nodes represent blending operations that operate on the nodes pointed to by their
136 operand properties.
137
138 To associate a blend tree with a QBlendedClipAnimator, set the animator's blendTree property to
139 point at the root node of your blend tree:
140
141 \badcode
142 auto blendTreeRoot = new QAdditiveClipBlend();
143 ...
144 auto animator = new QBlendedClipAnimator();
145 animator->setBlendTree(blendTreeRoot);
146 \endcode
147
148 A blend tree can be constructed from the following node types:
149
150 \note The blend node tree should only be edited when the animator is not running.
151
152 \list
153 \li Qt3DAnimation::QClipBlendValue
154 \li Qt3DAnimation::QLerpClipBlend
155 \li Qt3DAnimation::QAdditiveClipBlend
156 \endlist
157
158 Additional node types will be added over time.
159
160 As an example consider the following blend tree:
161
162 \badcode
163 Clip0----
164 |
165 Lerp Node----
166 | |
167 Clip1---- Additive Node
168 |
169 Clip2----
170 \endcode
171
172 This can be created and used as follows:
173
174 \code
175 // Create leaf nodes of blend tree
176 auto clip0 = new QClipBlendValue(
177 new QAnimationClipLoader(QUrl::fromLocalFile("walk.json")));
178 auto clip1 = new QClipBlendValue(
179 new QAnimationClipLoader(QUrl::fromLocalFile("run.json")));
180 auto clip2 = new QClipBlendValue(
181 new QAnimationClipLoader(QUrl::fromLocalFile("wave-arm.json")));
182
183 // Create blend tree inner nodes
184 auto lerpNode = new QLerpClipBlend();
185 lerpNode->setStartClip(clip0);
186 lerpNode->setEndClip(clip1);
187 lerpNode->setBlendFactor(0.5f); // Half-walk, half-run
188
189 auto additiveNode = new QAdditiveClipBlend();
190 additiveNode->setBaseClip(lerpNode); // Comes from lerp sub-tree
191 additiveNode->setAdditiveClip(clip2);
192 additiveNode->setAdditiveFactor(1.0f); // Wave arm fully
193
194 // Run the animator
195 auto animator = new QBlendedClipAnimator();
196 animator->setBlendTree(additiveNode);
197 animator->setChannelMapper(...);
198 animator->setRunning(true);
199 \endcode
200
201 By authoring a set of animation clips and blending between them dynamically at runtime with a
202 blend tree, we open up a huge set of possible resulting animations. As some simple examples of
203 the above blend tree, where alpha is the additive factor and beta is the lerp blend factor we
204 can get a 2D continuum of possible animations:
205
206 \badcode
207 (alpha = 0, beta = 1) Running, No arm waving --- (alpha = 1, beta = 1) Running, Arm waving
208 | |
209 | |
210 | |
211 (alpha = 0, beta = 0) Walking, No arm waving --- (alpha = 0, beta = 1) Running, No arm waving
212 \endcode
213
214 More complex blend trees offer even more flexibility for combining your animation clips. Note
215 that the values used to control the blend tree (alpha and beta above) are simple properties on
216 the blend nodes. This means, that these properties themselves can also be controlled by
217 the animation framework.
218
219*/
220QBlendedClipAnimator::QBlendedClipAnimator(Qt3DCore::QNode *parent)
221 : Qt3DAnimation::QAbstractClipAnimator(*new QBlendedClipAnimatorPrivate, parent)
222{
223}
224
225/*! \internal */
226QBlendedClipAnimator::QBlendedClipAnimator(QBlendedClipAnimatorPrivate &dd, Qt3DCore::QNode *parent)
227 : Qt3DAnimation::QAbstractClipAnimator(dd, parent)
228{
229}
230
231QBlendedClipAnimator::~QBlendedClipAnimator()
232{
233}
234
235/*!
236 \qmlproperty AbstractClipBlendNode Qt3D.Animation::BlendedClipAnimator::blendTree
237
238 This property holds the root of the animation blend tree that will
239 be evaluated before being interpolated by the animator.
240*/
241/*!
242 \property QBlendedClipAnimator::blendTree
243
244 This property holds the root of the animation blend tree that will be evaluated before being
245 interpolated by the animator.
246*/
247QAbstractClipBlendNode *QBlendedClipAnimator::blendTree() const
248{
249 Q_D(const QBlendedClipAnimator);
250 return d->m_blendTreeRoot;
251}
252
253void QBlendedClipAnimator::setBlendTree(QAbstractClipBlendNode *blendTree)
254{
255 Q_D(QBlendedClipAnimator);
256 if (d->m_blendTreeRoot == blendTree)
257 return;
258
259 if (d->m_blendTreeRoot)
260 d->unregisterDestructionHelper(node: d->m_blendTreeRoot);
261
262 if (blendTree != nullptr && blendTree->parent() == nullptr)
263 blendTree->setParent(this);
264
265 d->m_blendTreeRoot = blendTree;
266
267 if (d->m_blendTreeRoot)
268 d->registerDestructionHelper(node: d->m_blendTreeRoot, func: &QBlendedClipAnimator::setBlendTree, d->m_blendTreeRoot);
269
270 emit blendTreeChanged(blendTree);
271}
272
273} // namespace Qt3DAnimation
274
275QT_END_NAMESPACE
276
277#include "moc_qblendedclipanimator.cpp"
278

source code of qt3d/src/animation/frontend/qblendedclipanimator.cpp