summaryrefslogtreecommitdiffstats
path: root/src/animation
diff options
context:
space:
mode:
authorJuan José Casafranca <juan.casafranca@kdab.com>2017-09-10 14:52:46 +0200
committerSean Harmer <sean.harmer@kdab.com>2017-10-06 12:10:05 +0000
commitf0153ae8b12cc68ed6e38a1d93b83bb235b5e501 (patch)
tree311ec5c364d87ffc36b567986af3ff9823b3bbf1 /src/animation
parentc9bc1d866d69092f4fafe626687fe0f5746c829a (diff)
Fix animation local time calculation when changing playbackRate
Animation local time was computed in absolute mode, as a scale of the global time that has passed since the start of the animation. Now is computed relative to the last local time, as the last local time + a scale of the elapsed global time. Change-Id: I5c29002602a5184174618ac7755ec94f5c7a328f Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Diffstat (limited to 'src/animation')
-rw-r--r--src/animation/backend/animationutils.cpp49
-rw-r--r--src/animation/backend/animationutils_p.h20
-rw-r--r--src/animation/backend/blendedclipanimator.cpp27
-rw-r--r--src/animation/backend/blendedclipanimator_p.h13
-rw-r--r--src/animation/backend/clipanimator.cpp23
-rw-r--r--src/animation/backend/clipanimator_p.h12
-rw-r--r--src/animation/backend/evaluateblendclipanimatorjob.cpp30
-rw-r--r--src/animation/backend/evaluateblendclipanimatorjob_p.h3
-rw-r--r--src/animation/backend/evaluateclipanimatorjob.cpp14
-rw-r--r--src/animation/backend/evaluateclipanimatorjob_p.h3
10 files changed, 143 insertions, 51 deletions
diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp
index 3e255308b..fb5b19a5d 100644
--- a/src/animation/backend/animationutils.cpp
+++ b/src/animation/backend/animationutils.cpp
@@ -93,22 +93,26 @@ ClipEvaluationData evaluationDataForClip(AnimationClip *clip,
{
// global time values expected in seconds
ClipEvaluationData result;
- result.localTime = localTimeFromGlobalTime(animatorData.globalTime, animatorData.startTime,
- animatorData.playbackRate, clip->duration(),
- animatorData.loopCount, result.currentLoop);
+ result.currentLoop = animatorData.currentLoop;
+ result.localTime = localTimeFromElapsedTime(animatorData.currentTime, animatorData.elapsedTime,
+ animatorData.playbackRate, clip->duration(),
+ animatorData.loopCount, result.currentLoop);
result.isFinalFrame = isFinalFrame(result.localTime, clip->duration(),
result.currentLoop, animatorData.loopCount);
return result;
}
-double localTimeFromGlobalTime(double t_global,
- double t_start_global,
- double playbackRate,
- double duration,
- int loopCount,
- int &currentLoop)
+double localTimeFromElapsedTime(double t_current_local,
+ double t_elapsed_global,
+ double playbackRate,
+ double duration,
+ int loopCount,
+ int &currentLoop)
{
- double t_local = playbackRate * (t_global - t_start_global);
+ // Calculate the new local time.
+ // playhead + rate * dt
+ // where playhead is completed loops * duration + current loop local time
+ double t_local = currentLoop * duration + t_current_local + playbackRate * t_elapsed_global;
double loopNumber = 0;
if (loopCount == 1) {
t_local = qBound(0.0, t_local, duration);
@@ -123,28 +127,30 @@ double localTimeFromGlobalTime(double t_global,
t_local = std::fmod(t_local, duration);
// Ensure we clamp to end of final loop
- if (loopNumber == loopCount) {
+ if (int(loopNumber) == loopCount) {
loopNumber = loopCount - 1;
t_local = duration;
}
}
- qCDebug(Jobs) << "t_global - t_start =" << t_global - t_start_global
- << "current loop =" << loopNumber
+ qCDebug(Jobs) << "current loop =" << loopNumber
<< "t =" << t_local
<< "duration =" << duration;
- currentLoop = loopNumber;
+ currentLoop = int(loopNumber);
return t_local;
}
-double phaseFromGlobalTime(double t_global, double t_start_global,
- double playbackRate, double duration,
- int loopCount, int &currentLoop)
+double phaseFromElapsedTime(double t_current_local,
+ double t_elapsed_global,
+ double playbackRate,
+ double duration,
+ int loopCount,
+ int &currentLoop)
{
- const double t_local = localTimeFromGlobalTime(t_global, t_start_global, playbackRate,
- duration, loopCount, currentLoop);
+ const double t_local = localTimeFromElapsedTime(t_current_local, t_elapsed_global, playbackRate,
+ duration, loopCount, currentLoop);
return t_local / duration;
}
@@ -455,6 +461,11 @@ QVector<MappingData> buildPropertyMappings(const QVector<ChannelMapping*> &chann
const ChannelNameAndType nameAndType = { mapping->channelName(), mapping->type() };
const int index = channelNamesAndTypes.indexOf(nameAndType);
if (index != -1) {
+ // Do we have any animation data for this channel? If not, don't bother
+ // adding a mapping for it.
+ if (channelComponentIndices[index].isEmpty())
+ continue;
+
// We got one!
mappingData.channelIndices = channelComponentIndices[index];
mappingDataVec.push_back(mappingData);
diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h
index fb9e44680..d8127d8af 100644
--- a/src/animation/backend/animationutils_p.h
+++ b/src/animation/backend/animationutils_p.h
@@ -106,9 +106,10 @@ inline QDebug operator<<(QDebug dbg, const MappingData &mapping)
struct AnimatorEvaluationData
{
- double globalTime;
- double startTime;
+ double elapsedTime;
+ double currentTime;
int loopCount;
+ int currentLoop;
double playbackRate;
};
@@ -157,14 +158,15 @@ struct AnimationCallbackAndValue
};
template<typename Animator>
-AnimatorEvaluationData evaluationDataForAnimator(Animator animator, Clock* clock, qint64 globalTime)
+AnimatorEvaluationData evaluationDataForAnimator(Animator animator, Clock* clock, qint64 nsSincePreviousFrame)
{
AnimatorEvaluationData data;
data.loopCount = animator->loops();
+ data.currentLoop = animator->currentLoop();
data.playbackRate = clock != nullptr ? clock->playbackRate() : 1.0;
// Convert global time from nsec to sec
- data.startTime = double(animator->startTime()) / 1.0e9;
- data.globalTime = double(globalTime) / 1.0e9;
+ data.elapsedTime = double(nsSincePreviousFrame) / 1.0e9;
+ data.currentTime = animator->lastLocalTime();
return data;
}
@@ -227,12 +229,12 @@ Q_AUTOTEST_EXPORT
QVector<ComponentIndices> assignChannelComponentIndices(const QVector<ChannelNameAndType> &namesAndTypes);
Q_AUTOTEST_EXPORT
-double localTimeFromGlobalTime(double t_global, double t_start_global,
- double playbackRate, double duration,
- int loopCount, int &currentLoop);
+double localTimeFromElapsedTime(double t_current_local, double t_elapsed_global,
+ double playbackRate, double duration,
+ int loopCount, int &currentLoop);
Q_AUTOTEST_EXPORT
-double phaseFromGlobalTime(double t_global, double t_start_global,
+double phaseFromElapsedTime(double t_current_local, double t_elapsed_global,
double playbackRate, double duration,
int loopCount, int &currentLoop);
diff --git a/src/animation/backend/blendedclipanimator.cpp b/src/animation/backend/blendedclipanimator.cpp
index ec0a5027a..1487d6c3e 100644
--- a/src/animation/backend/blendedclipanimator.cpp
+++ b/src/animation/backend/blendedclipanimator.cpp
@@ -48,7 +48,8 @@ namespace Animation {
BlendedClipAnimator::BlendedClipAnimator()
: BackendNode(ReadWrite)
, m_running(false)
- , m_startGlobalTime(0)
+ , m_lastGlobalTimeNS(0)
+ , m_lastLocalTime(0.0)
, m_currentLoop(0)
, m_loops(1)
{
@@ -66,6 +67,26 @@ void BlendedClipAnimator::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeB
setDirty(Handler::BlendedClipAnimatorDirty);
}
+double BlendedClipAnimator::lastLocalTime() const
+{
+ return m_lastLocalTime;
+}
+
+void BlendedClipAnimator::setLastLocalTime(double lastLocalTime)
+{
+ m_lastLocalTime = lastLocalTime;
+}
+
+void BlendedClipAnimator::setLastGlobalTimeNS(const qint64 &lastGlobalTimeNS)
+{
+ m_lastGlobalTimeNS = lastGlobalTimeNS;
+}
+
+qint64 BlendedClipAnimator::nsSincePreviousFrame(qint64 currentGlobalTimeNS)
+{
+ return currentGlobalTimeNS - m_lastGlobalTimeNS;
+}
+
void BlendedClipAnimator::cleanup()
{
setEnabled(false);
@@ -74,7 +95,8 @@ void BlendedClipAnimator::cleanup()
m_mapperId = Qt3DCore::QNodeId();
m_clockId = Qt3DCore::QNodeId();
m_running = false;
- m_startGlobalTime = 0;
+ m_lastGlobalTimeNS = 0;
+ m_lastLocalTime = 0.0;
m_currentLoop = 0;
m_loops = 1;
}
@@ -124,6 +146,7 @@ void BlendedClipAnimator::sendCallbacks(const QVector<AnimationCallbackAndValue>
}
}
+
Qt3DCore::QNodeId BlendedClipAnimator::blendTreeRootId() const
{
return m_blendTreeRootId;
diff --git a/src/animation/backend/blendedclipanimator_p.h b/src/animation/backend/blendedclipanimator_p.h
index d9f89b5f9..dd99c4274 100644
--- a/src/animation/backend/blendedclipanimator_p.h
+++ b/src/animation/backend/blendedclipanimator_p.h
@@ -79,8 +79,7 @@ public:
void setClockId(Qt3DCore::QNodeId clockId);
void setRunning(bool running);
- void setStartTime(qint64 globalTime) { m_startGlobalTime = globalTime; }
- qint64 startTime() const { return m_startGlobalTime; }
+ void setStartTime(qint64 globalTime) { m_lastGlobalTimeNS = globalTime; }
void setLoops(int loops) { m_loops = loops; }
int loops() const { return m_loops; }
@@ -96,6 +95,12 @@ public:
void animationClipMarkedDirty() { setDirty(Handler::BlendedClipAnimatorDirty); }
+ qint64 nsSincePreviousFrame(qint64 currentGlobalTimeNS);
+ void setLastGlobalTimeNS(const qint64 &lastGlobalTimeNS);
+
+ double lastLocalTime() const;
+ void setLastLocalTime(double lastLocalTime);
+
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
Qt3DCore::QNodeId m_blendTreeRootId;
@@ -103,7 +108,9 @@ private:
Qt3DCore::QNodeId m_clockId;
bool m_running;
- qint64 m_startGlobalTime;
+ qint64 m_lastGlobalTimeNS;
+ double m_lastLocalTime;
+
int m_currentLoop;
int m_loops;
diff --git a/src/animation/backend/clipanimator.cpp b/src/animation/backend/clipanimator.cpp
index 568e2dbb0..21c08b80a 100644
--- a/src/animation/backend/clipanimator.cpp
+++ b/src/animation/backend/clipanimator.cpp
@@ -56,7 +56,8 @@ ClipAnimator::ClipAnimator()
, m_clockId()
, m_running(false)
, m_loops(1)
- , m_startGlobalTime(0)
+ , m_lastGlobalTimeNS(0)
+ , m_lastLocalTime(0.0)
, m_mappingData()
, m_currentLoop(0)
{
@@ -162,6 +163,26 @@ void ClipAnimator::sendCallbacks(const QVector<AnimationCallbackAndValue> &callb
}
}
+qint64 ClipAnimator::nsSincePreviousFrame(qint64 currentGlobalTimeNS)
+{
+ return currentGlobalTimeNS - m_lastGlobalTimeNS;
+}
+
+void ClipAnimator::setLastGlobalTimeNS(qint64 lastGlobalTimeNS)
+{
+ m_lastGlobalTimeNS = lastGlobalTimeNS;
+}
+
+double ClipAnimator::lastLocalTime() const
+{
+ return m_lastLocalTime;
+}
+
+void ClipAnimator::setLastLocalTime(double lastLocalTime)
+{
+ m_lastLocalTime = lastLocalTime;
+}
+
} // namespace Animation
} // namespace Qt3DAnimation
diff --git a/src/animation/backend/clipanimator_p.h b/src/animation/backend/clipanimator_p.h
index 8a08969ba..0f7380d66 100644
--- a/src/animation/backend/clipanimator_p.h
+++ b/src/animation/backend/clipanimator_p.h
@@ -86,8 +86,7 @@ public:
void setMappingData(const QVector<MappingData> &mappingData) { m_mappingData = mappingData; }
QVector<MappingData> mappingData() const { return m_mappingData; }
- void setStartTime(qint64 globalTime) { m_startGlobalTime = globalTime; }
- qint64 startTime() const { return m_startGlobalTime; }
+ void setStartTime(qint64 globalTime) { m_lastGlobalTimeNS = globalTime; }
int currentLoop() const { return m_currentLoop; }
void setCurrentLoop(int currentLoop) { m_currentLoop = currentLoop; }
@@ -100,6 +99,12 @@ public:
void setFormatIndices(const ComponentIndices &formatIndices) { m_formatIndices = formatIndices; }
ComponentIndices formatIndices() const { return m_formatIndices; }
+ qint64 nsSincePreviousFrame(qint64 currentGlobalTimeNS);
+ void setLastGlobalTimeNS(qint64 lastGlobalTimeNS);
+
+ double lastLocalTime() const;
+ void setLastLocalTime(double lastLocalTime);
+
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
@@ -110,7 +115,8 @@ private:
int m_loops;
// Working state
- qint64 m_startGlobalTime;
+ qint64 m_lastGlobalTimeNS;
+ double m_lastLocalTime;
QVector<MappingData> m_mappingData;
int m_currentLoop;
diff --git a/src/animation/backend/evaluateblendclipanimatorjob.cpp b/src/animation/backend/evaluateblendclipanimatorjob.cpp
index be05f7ec0..3cde7b32f 100644
--- a/src/animation/backend/evaluateblendclipanimatorjob.cpp
+++ b/src/animation/backend/evaluateblendclipanimatorjob.cpp
@@ -51,6 +51,8 @@ namespace Animation {
EvaluateBlendClipAnimatorJob::EvaluateBlendClipAnimatorJob()
: Qt3DCore::QAspectJob()
+ , m_currentGlobalTime(0.0)
+ , m_lastGlobalTime(0.0)
{
SET_JOB_RUN_STAT_TYPE(this, JobTypes::EvaluateBlendClipAnimator, 0);
}
@@ -62,7 +64,15 @@ void EvaluateBlendClipAnimatorJob::run()
// TODO: We should be able to cache this for each blend animator and only
// update when a node indicates its dependencies have changed as a result
// of blend factors changing
+
BlendedClipAnimator *blendedClipAnimator = m_handler->blendedClipAnimatorManager()->data(m_blendClipAnimatorHandle);
+ Q_ASSERT(blendedClipAnimator);
+ if (!blendedClipAnimator->isRunning())
+ return;
+
+ qint64 globalTimeNS = m_handler->simulationTime();
+ qint64 nsSincePreviousFrame = blendedClipAnimator->nsSincePreviousFrame(globalTimeNS);
+
Qt3DCore::QNodeId blendTreeRootId = blendedClipAnimator->blendTreeRootId();
const QVector<Qt3DCore::QNodeId> valueNodeIdsToEvaluate = gatherValueNodesToEvaluate(m_handler, blendTreeRootId);
@@ -75,15 +85,12 @@ void EvaluateBlendClipAnimatorJob::run()
Clock *clock = m_handler->clockManager()->lookupResource(blendedClipAnimator->clockId());
// Calculate the phase given the blend tree duration and global time
- const qint64 globalTime = m_handler->simulationTime();
- const AnimatorEvaluationData animatorData = evaluationDataForAnimator(blendedClipAnimator, clock, globalTime);
- int currentLoop = 0;
- const double phase = phaseFromGlobalTime(animatorData.globalTime,
- animatorData.startTime,
- animatorData.playbackRate,
- duration,
- animatorData.loopCount,
- currentLoop);
+ AnimatorEvaluationData animatorData = evaluationDataForAnimator(blendedClipAnimator, clock, nsSincePreviousFrame);
+ const double phase = phaseFromElapsedTime(animatorData.currentTime, animatorData.elapsedTime,
+ animatorData.playbackRate,
+ duration,
+ animatorData.loopCount,
+ animatorData.currentLoop);
// Iterate over the value nodes of the blend tree, evaluate the
// contained animation clips at the current phase and store the results
@@ -107,7 +114,10 @@ void EvaluateBlendClipAnimatorJob::run()
ClipResults blendedResults = evaluateBlendTree(m_handler, blendedClipAnimator, blendTreeRootId);
const double localTime = phase * duration;
- const bool finalFrame = isFinalFrame(localTime, duration, currentLoop, animatorData.loopCount);
+ blendedClipAnimator->setLastGlobalTimeNS(globalTimeNS);
+ blendedClipAnimator->setLastLocalTime(localTime);
+ blendedClipAnimator->setCurrentLoop(animatorData.currentLoop);
+ const bool finalFrame = isFinalFrame(localTime, duration, animatorData.currentLoop, animatorData.loopCount);
// Prepare the property change events
const QVector<MappingData> mappingData = blendedClipAnimator->mappingData();
diff --git a/src/animation/backend/evaluateblendclipanimatorjob_p.h b/src/animation/backend/evaluateblendclipanimatorjob_p.h
index a7822c8f9..ff578e517 100644
--- a/src/animation/backend/evaluateblendclipanimatorjob_p.h
+++ b/src/animation/backend/evaluateblendclipanimatorjob_p.h
@@ -78,6 +78,9 @@ protected:
private:
HBlendedClipAnimator m_blendClipAnimatorHandle;
Handler *m_handler;
+
+ qint64 m_currentGlobalTime;
+ qint64 m_lastGlobalTime;
};
typedef QSharedPointer<EvaluateBlendClipAnimatorJob> EvaluateBlendClipAnimatorJobPtr;
diff --git a/src/animation/backend/evaluateclipanimatorjob.cpp b/src/animation/backend/evaluateclipanimatorjob.cpp
index d9600c375..972762033 100644
--- a/src/animation/backend/evaluateclipanimatorjob.cpp
+++ b/src/animation/backend/evaluateclipanimatorjob.cpp
@@ -48,6 +48,8 @@ namespace Animation {
EvaluateClipAnimatorJob::EvaluateClipAnimatorJob()
: Qt3DCore::QAspectJob()
+ , m_currentGlobalTime(0.0)
+ , m_lastGlobalTime(0.0)
{
SET_JOB_RUN_STAT_TYPE(this, JobTypes::EvaluateClipAnimator, 0);
}
@@ -56,11 +58,13 @@ void EvaluateClipAnimatorJob::run()
{
Q_ASSERT(m_handler);
- const qint64 globalTime = m_handler->simulationTime();
- //qDebug() << Q_FUNC_INFO << "t_global =" << globalTime;
-
ClipAnimator *clipAnimator = m_handler->clipAnimatorManager()->data(m_clipAnimatorHandle);
Q_ASSERT(clipAnimator);
+ if (!clipAnimator->isRunning())
+ return;
+
+ qint64 globalTimeNS = m_handler->simulationTime();
+ qint64 nsSincePreviousFrame = clipAnimator->nsSincePreviousFrame(globalTimeNS);
Clock *clock = m_handler->clockManager()->lookupResource(clipAnimator->clockId());
@@ -68,7 +72,7 @@ void EvaluateClipAnimatorJob::run()
AnimationClip *clip = m_handler->animationClipLoaderManager()->lookupResource(clipAnimator->clipId());
Q_ASSERT(clip);
// Prepare for evaluation (convert global time to local time ....)
- const AnimatorEvaluationData animatorEvaluationData = evaluationDataForAnimator(clipAnimator, clock, globalTime);
+ const AnimatorEvaluationData animatorEvaluationData = evaluationDataForAnimator(clipAnimator, clock, nsSincePreviousFrame);
const ClipEvaluationData preEvaluationDataForClip = evaluationDataForClip(clip, animatorEvaluationData);
const ClipResults rawClipResults = evaluateClipAtLocalTime(clip, preEvaluationDataForClip.localTime);
@@ -80,6 +84,8 @@ void EvaluateClipAnimatorJob::run()
clipAnimator->setRunning(false);
clipAnimator->setCurrentLoop(preEvaluationDataForClip.currentLoop);
+ clipAnimator->setLastGlobalTimeNS(globalTimeNS);
+ clipAnimator->setLastLocalTime(preEvaluationDataForClip.localTime);
// Prepare property changes (if finalFrame it also prepares the change for the running property for the frontend)
const QVector<Qt3DCore::QSceneChangePtr> changes = preparePropertyChanges(clipAnimator->peerId(),
diff --git a/src/animation/backend/evaluateclipanimatorjob_p.h b/src/animation/backend/evaluateclipanimatorjob_p.h
index 866032dd1..911341788 100644
--- a/src/animation/backend/evaluateclipanimatorjob_p.h
+++ b/src/animation/backend/evaluateclipanimatorjob_p.h
@@ -82,6 +82,9 @@ protected:
private:
HClipAnimator m_clipAnimatorHandle;
Handler *m_handler;
+
+ qint64 m_currentGlobalTime;
+ qint64 m_lastGlobalTime;
};
} // namespace Animation