diff options
author | Sean Harmer <sean.harmer@kdab.com> | 2017-03-15 18:38:45 +0000 |
---|---|---|
committer | Sean Harmer <sean.harmer@kdab.com> | 2017-03-25 14:24:08 +0000 |
commit | f743cf2833f42c8ac2c6c8ce5a198bbb5e3050e6 (patch) | |
tree | f7a93b8c85c1012ddf64e1c9d03d13bd5535cac2 /src/animation/backend/evaluateblendclipanimatorjob.cpp | |
parent | 14538a90120d7d1e8f37c0740d8a6a669389caad (diff) |
Implement the new blend tree prep and evaluation jobs
Change-Id: Ic619cfdc27d7c3c46d96d3cc0e83e9134ebb0216
Reviewed-by: Mike Krus <mike.krus@kdab.com>
Diffstat (limited to 'src/animation/backend/evaluateblendclipanimatorjob.cpp')
-rw-r--r-- | src/animation/backend/evaluateblendclipanimatorjob.cpp | 200 |
1 files changed, 51 insertions, 149 deletions
diff --git a/src/animation/backend/evaluateblendclipanimatorjob.cpp b/src/animation/backend/evaluateblendclipanimatorjob.cpp index a6ac5959f..08e6689ca 100644 --- a/src/animation/backend/evaluateblendclipanimatorjob.cpp +++ b/src/animation/backend/evaluateblendclipanimatorjob.cpp @@ -39,6 +39,7 @@ #include <Qt3DAnimation/private/managers_p.h> #include <Qt3DAnimation/private/animationlogging_p.h> #include <Qt3DAnimation/private/animationutils_p.h> +#include <Qt3DAnimation/private/clipblendvalue_p.h> #include <Qt3DAnimation/private/lerpclipblend_p.h> #include <Qt3DAnimation/private/clipblendnodevisitor_p.h> #include <Qt3DAnimation/private/job_common_p.h> @@ -50,168 +51,69 @@ namespace Animation { EvaluateBlendClipAnimatorJob::EvaluateBlendClipAnimatorJob() : Qt3DCore::QAspectJob() - , m_currentLoop(std::numeric_limits<int>::max()) - , m_isFinalFrame(true) { SET_JOB_RUN_STAT_TYPE(this, JobTypes::EvaluateBlendClipAnimator, 0); } -namespace { - -ClipResults blendValuesBasedOnMappings(ClipBlendNode *node, - const ClipResults &channelResults1, - const ClipResults &channelResults2, - const QVector<BlendingMappingData> &blendingMappingData) -{ - ClipResults blendedValues; - blendedValues.reserve(blendingMappingData.size()); - - // Build a combined vector of blended value - for (const BlendingMappingData &mapping : blendingMappingData) { - - switch (mapping.blendAction) { - case BlendingMappingData::ClipBlending: { - Q_ASSERT(mapping.channelIndicesClip1.size() == mapping.channelIndicesClip2.size()); - for (int i = 0, m = mapping.channelIndicesClip1.size(); i < m; ++i) { - const float value1 = channelResults1.at(mapping.channelIndicesClip1[i]); - const float value2 = channelResults2.at(mapping.channelIndicesClip2[i]); - const float blendedValue = node->blend(value1, value2); - blendedValues.push_back(blendedValue); - } - break; - } - case BlendingMappingData::NoBlending: { - const bool useClip1 = !mapping.channelIndicesClip1.empty(); - const QVector<int> channelIndices = useClip1 ? mapping.channelIndicesClip1 : mapping.channelIndicesClip2; - const QVector<float> values = useClip1 ? channelResults1 : channelResults2; - for (int i = 0, m = channelIndices.size(); i < m; ++i) { - const float value = values.at(channelIndices[i]); - blendedValues.push_back(value); - } - break; - } - default: - Q_UNREACHABLE(); - break; - } - } - return blendedValues; -} - -QVector<MappingData> fromBlendingMappingData(const QVector<BlendingMappingData> &blendingMappingData) -{ - const int blendingMappingDataSize = blendingMappingData.size(); - QVector<MappingData> mappingData(blendingMappingDataSize); - for (int i = 0; i < blendingMappingDataSize; ++i) { - mappingData[i] = blendingMappingData[i]; - } - return mappingData; -} - -} // anonymous - -void EvaluateBlendClipAnimatorJob::blendClips(ClipBlendNode *node, - const BlendedClipAnimator::BlendNodeData &nodeData, - const AnimatorEvaluationData &animatorEvaluationData) -{ - AnimationClipLoader *clip1 = m_handler->animationClipLoaderManager()->lookupResource(nodeData.left); - AnimationClipLoader *clip2 = m_handler->animationClipLoaderManager()->lookupResource(nodeData.right); - Q_ASSERT(clip1 && clip2); - - // Prepare for evaluation (convert global time to local time ....) - const ClipEvaluationData preEvaluationDataForClip1 = evaluationDataForClip(clip1, animatorEvaluationData); - const ClipEvaluationData preEvaluationDataForClip2 = evaluationDataForClip(clip2, animatorEvaluationData); - - // Evaluate the fcurves for both clip - const ClipResults channelResultsClip1 = evaluateClipAtLocalTime(clip1, preEvaluationDataForClip1.localTime); - const ClipResults channelResultsClip2 = evaluateClipAtLocalTime(clip2, preEvaluationDataForClip2.localTime); - - // Update loops and running of the animator - m_currentLoop = std::min(m_currentLoop, std::min(preEvaluationDataForClip1.currentLoop, preEvaluationDataForClip2.currentLoop)); - // isFinalFrame remains true only if all the clips have reached their final frame - m_isFinalFrame &= (preEvaluationDataForClip1.isFinalFrame && preEvaluationDataForClip2.isFinalFrame); - - const QVector<BlendingMappingData> blendingMappingData = nodeData.mappingData; - // Perform blending between the two clips - const QVector<float> blendedValues = blendValuesBasedOnMappings(node, channelResultsClip1, - channelResultsClip2, blendingMappingData); - - m_clipBlendResultsTable.insert(node, blendedValues); -} - -void EvaluateBlendClipAnimatorJob::blendNodes(ClipBlendNode *node, const BlendedClipAnimator::BlendNodeData &nodeData) -{ - ClipBlendNode *node1 = m_handler->clipBlendNodeManager()->lookupNode(nodeData.left); - ClipBlendNode *node2 = m_handler->clipBlendNodeManager()->lookupNode(nodeData.right); - Q_ASSERT(node1 && node2); - - // Retrieve results for the childNodes - const ClipResults channelResultsNode1 = m_clipBlendResultsTable.take(node1); - const ClipResults channelResultsNode2 = m_clipBlendResultsTable.take(node2); - - // Build a combined vector of blended value - const QVector<BlendingMappingData> blendingMappingData = nodeData.mappingData; - // Perform blending between the two nodes - const QVector<float> blendedValues = blendValuesBasedOnMappings(node, channelResultsNode1, - channelResultsNode2, blendingMappingData); - - m_clipBlendResultsTable.insert(node, blendedValues); -} - void EvaluateBlendClipAnimatorJob::run() { - const qint64 globalTime = m_handler->simulationTime(); - + // Find the set of clips that need to be evaluated by querying each node + // in the blend tree. + // 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); - - const AnimatorEvaluationData animatorEvaluationData = evaluationDataForAnimator(blendedClipAnimator, globalTime); - const QHash<Qt3DCore::QNodeId, BlendedClipAnimator::BlendNodeData> blendindNodeTable = blendedClipAnimator->blendTreeTable(); - - // Reset globals - m_currentLoop = std::numeric_limits<int>::max(); - m_isFinalFrame = true; + Qt3DCore::QNodeId blendTreeRootId = blendedClipAnimator->blendTreeRootId(); + const QVector<Qt3DCore::QNodeId> valueNodeIdsToEvaluate = gatherValueNodesToEvaluate(m_handler, blendTreeRootId); - // Perform blending of the tree (Post-order traversal) - ClipBlendNodeVisitor visitor(m_handler->clipBlendNodeManager()); - visitor.traverse(blendedClipAnimator->blendTreeRootId(), [&, this] (ClipBlendNode *blendNode) { - // Retrieve BlendingData for the not - const BlendedClipAnimator::BlendNodeData &nodeData = blendindNodeTable.value(blendNode->peerId()); + // Calculate the resulting duration of the blend tree based upon its current state + ClipBlendNodeManager *blendNodeManager = m_handler->clipBlendNodeManager(); + ClipBlendNode *blendTreeRootNode = blendNodeManager->lookupNode(blendTreeRootId); + Q_ASSERT(blendTreeRootNode); + const double duration = blendTreeRootNode->duration(); - switch (nodeData.type) { - case BlendedClipAnimator::BlendNodeData::BlendNodeType: - // Blend two ClipBlendNode - blendNodes(blendNode, nodeData); - break; - case BlendedClipAnimator::BlendNodeData::ClipType: // Leaf - // Blend two clips - blendClips(blendNode, nodeData, animatorEvaluationData); - break; - default: - Q_UNREACHABLE(); - break; - } - }); - - - // Set current loop and running if need - if (m_isFinalFrame) - blendedClipAnimator->setRunning(false); - blendedClipAnimator->setCurrentLoop(m_currentLoop); + // Calculate the phase given the blend tree duration and global time + const qint64 globalTime = m_handler->simulationTime(); + const AnimatorEvaluationData animatorData = evaluationDataForAnimator(blendedClipAnimator, globalTime); + int currentLoop = 0; + const double phase = phaseFromGlobalTime(animatorData.globalTime, + animatorData.startTime, + animatorData.playbackRate, + duration, + animatorData.loopCount, + currentLoop); + + // Iterate over the value nodes of the blend tree, evaluate the + // contained animation clips at the current phase and store the results + // in the animator indexed by node. + // TODO: Handle clips not loaded from file + AnimationClipLoaderManager *clipLoaderManager = m_handler->animationClipLoaderManager(); + for (const auto valueNodeId : valueNodeIdsToEvaluate) { + ClipBlendValue *valueNode = static_cast<ClipBlendValue *>(blendNodeManager->lookupNode(valueNodeId)); + Q_ASSERT(valueNode); + AnimationClipLoader *clip = clipLoaderManager->lookupResource(valueNode->clipId()); + Q_ASSERT(clip); + + ClipResults rawClipResults = evaluateClipAtPhase(clip, phase); + + // Reformat the clip results into the layout used by this animator/blend tree + ComponentIndices format = valueNode->formatIndices(blendedClipAnimator->peerId()); + ClipResults formattedClipResults = formatClipResults(rawClipResults, format); + valueNode->setClipResults(blendedClipAnimator->peerId(), formattedClipResults); + } - // Prepare property changes using the root node which should now be filled with correct values - ClipBlendNode *rootBlendNode = m_handler->clipBlendNodeManager()->lookupNode(blendedClipAnimator->blendTreeRootId()); - Q_ASSERT(m_clipBlendResultsTable.size() == 1 && m_clipBlendResultsTable.contains(rootBlendNode)); + // Evaluate the blend tree + ClipResults blendedResults = evaluateBlendTree(m_handler, blendedClipAnimator, blendTreeRootId); - const ClipResults blendedValues = m_clipBlendResultsTable.take(rootBlendNode); - const BlendedClipAnimator::BlendNodeData &rootNodeData = blendindNodeTable.value(rootBlendNode->peerId()); - const QVector<MappingData> mappingData = fromBlendingMappingData(rootNodeData.mappingData); + const double localTime = phase * duration; + const bool finalFrame = isFinalFrame(localTime, duration, currentLoop, animatorData.loopCount); - // Prepare property changes (if finalFrame it also prepares the change for the running property for the frontend) + // Prepare the property change events + const QVector<MappingData> mappingData = blendedClipAnimator->mappingData(); const QVector<Qt3DCore::QSceneChangePtr> changes = preparePropertyChanges(blendedClipAnimator->peerId(), - mappingData, - blendedValues, - m_isFinalFrame); + mappingData, + blendedResults, + finalFrame); // Send the property changes blendedClipAnimator->sendPropertyChanges(changes); } |