diff options
author | Juan José Casafranca <juan.casafranca@kdab.com> | 2017-09-10 14:52:46 +0200 |
---|---|---|
committer | Sean Harmer <sean.harmer@kdab.com> | 2017-10-06 12:10:05 +0000 |
commit | f0153ae8b12cc68ed6e38a1d93b83bb235b5e501 (patch) | |
tree | 311ec5c364d87ffc36b567986af3ff9823b3bbf1 /src | |
parent | c9bc1d866d69092f4fafe626687fe0f5746c829a (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')
-rw-r--r-- | src/animation/backend/animationutils.cpp | 49 | ||||
-rw-r--r-- | src/animation/backend/animationutils_p.h | 20 | ||||
-rw-r--r-- | src/animation/backend/blendedclipanimator.cpp | 27 | ||||
-rw-r--r-- | src/animation/backend/blendedclipanimator_p.h | 13 | ||||
-rw-r--r-- | src/animation/backend/clipanimator.cpp | 23 | ||||
-rw-r--r-- | src/animation/backend/clipanimator_p.h | 12 | ||||
-rw-r--r-- | src/animation/backend/evaluateblendclipanimatorjob.cpp | 30 | ||||
-rw-r--r-- | src/animation/backend/evaluateblendclipanimatorjob_p.h | 3 | ||||
-rw-r--r-- | src/animation/backend/evaluateclipanimatorjob.cpp | 14 | ||||
-rw-r--r-- | src/animation/backend/evaluateclipanimatorjob_p.h | 3 |
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 ¤tLoop) +double localTimeFromElapsedTime(double t_current_local, + double t_elapsed_global, + double playbackRate, + double duration, + int loopCount, + int ¤tLoop) { - 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 ¤tLoop) +double phaseFromElapsedTime(double t_current_local, + double t_elapsed_global, + double playbackRate, + double duration, + int loopCount, + int ¤tLoop) { - 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 ¤tLoop); +double localTimeFromElapsedTime(double t_current_local, double t_elapsed_global, + double playbackRate, double duration, + int loopCount, int ¤tLoop); 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 ¤tLoop); 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 |