From 9786954585c63c55a2628c85b0f265ead6f44ddd Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 31 Aug 2015 12:13:05 -0700 Subject: [PATCH] Added support for onDone and onLoop triggers. --- interface/src/avatar/MyAvatar.cpp | 7 ++++++- libraries/animation/src/AnimBlendLinear.cpp | 10 +++++----- libraries/animation/src/AnimBlendLinear.h | 2 +- libraries/animation/src/AnimClip.cpp | 14 ++++++++------ libraries/animation/src/AnimClip.h | 4 ++-- libraries/animation/src/AnimNode.h | 8 +++++--- libraries/animation/src/AnimOverlay.cpp | 6 +++--- libraries/animation/src/AnimOverlay.h | 2 +- libraries/animation/src/AnimStateMachine.cpp | 10 +++++++--- libraries/animation/src/AnimStateMachine.h | 2 +- libraries/animation/src/AnimVariant.h | 2 +- tests/animation/src/data/avatar.json | 20 ++++++++++---------- 12 files changed, 50 insertions(+), 37 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index fa5f4da702..c5435c590b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -176,7 +176,12 @@ void MyAvatar::update(float deltaTime) { } t += deltaTime; - _animNode->evaluate(_animVars, deltaTime); + AnimNode::Triggers triggers; + _animNode->evaluate(_animVars, deltaTime, triggers); + _animVars.clearTriggers(); + for (auto& trigger : triggers) { + _animVars.setTrigger(trigger); + } } if (_referential) { diff --git a/libraries/animation/src/AnimBlendLinear.cpp b/libraries/animation/src/AnimBlendLinear.cpp index 102d0e4df6..499579ae67 100644 --- a/libraries/animation/src/AnimBlendLinear.cpp +++ b/libraries/animation/src/AnimBlendLinear.cpp @@ -22,7 +22,7 @@ AnimBlendLinear::~AnimBlendLinear() { } -const AnimPoseVec& AnimBlendLinear::evaluate(const AnimVariantMap& animVars, float dt) { +const AnimPoseVec& AnimBlendLinear::evaluate(const AnimVariantMap& animVars, float dt, Triggers& triggersOut) { _alpha = animVars.lookup(_alphaVar, _alpha); @@ -31,7 +31,7 @@ const AnimPoseVec& AnimBlendLinear::evaluate(const AnimVariantMap& animVars, flo pose = AnimPose::identity; } } else if (_children.size() == 1) { - _poses = _children[0]->evaluate(animVars, dt); + _poses = _children[0]->evaluate(animVars, dt, triggersOut); } else { float clampedAlpha = glm::clamp(_alpha, 0.0f, (float)(_children.size() - 1)); size_t prevPoseIndex = glm::floor(clampedAlpha); @@ -39,11 +39,11 @@ const AnimPoseVec& AnimBlendLinear::evaluate(const AnimVariantMap& animVars, flo float alpha = glm::fract(clampedAlpha); if (prevPoseIndex == nextPoseIndex) { // this can happen if alpha is on an integer boundary - _poses = _children[prevPoseIndex]->evaluate(animVars, dt); + _poses = _children[prevPoseIndex]->evaluate(animVars, dt, triggersOut); } else { // need to eval and blend between two children. - auto prevPoses = _children[prevPoseIndex]->evaluate(animVars, dt); - auto nextPoses = _children[nextPoseIndex]->evaluate(animVars, dt); + auto prevPoses = _children[prevPoseIndex]->evaluate(animVars, dt, triggersOut); + auto nextPoses = _children[nextPoseIndex]->evaluate(animVars, dt, triggersOut); if (prevPoses.size() > 0 && prevPoses.size() == nextPoses.size()) { _poses.resize(prevPoses.size()); diff --git a/libraries/animation/src/AnimBlendLinear.h b/libraries/animation/src/AnimBlendLinear.h index 2df1965064..8016f7994f 100644 --- a/libraries/animation/src/AnimBlendLinear.h +++ b/libraries/animation/src/AnimBlendLinear.h @@ -29,7 +29,7 @@ public: AnimBlendLinear(const std::string& id, float alpha); virtual ~AnimBlendLinear() override; - virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, float dt) override; + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, float dt, Triggers& triggersOut) override; void setAlphaVar(const std::string& alphaVar) { _alphaVar = alphaVar; } diff --git a/libraries/animation/src/AnimClip.cpp b/libraries/animation/src/AnimClip.cpp index c4294495e7..12ba97f377 100644 --- a/libraries/animation/src/AnimClip.cpp +++ b/libraries/animation/src/AnimClip.cpp @@ -27,14 +27,14 @@ AnimClip::~AnimClip() { } -const AnimPoseVec& AnimClip::evaluate(const AnimVariantMap& animVars, float dt) { +const AnimPoseVec& AnimClip::evaluate(const AnimVariantMap& animVars, float dt, Triggers& triggersOut) { // lookup parameters from animVars, using current instance variables as defaults. _startFrame = animVars.lookup(_startFrameVar, _startFrame); _endFrame = animVars.lookup(_endFrameVar, _endFrame); _timeScale = animVars.lookup(_timeScaleVar, _timeScale); _loopFlag = animVars.lookup(_loopFlagVar, _loopFlag); - _frame = accumulateTime(animVars.lookup(_frameVar, _frame), dt); + _frame = accumulateTime(animVars.lookup(_frameVar, _frame), dt, triggersOut); // poll network anim to see if it's finished loading yet. if (_networkAnim && _networkAnim->isLoaded() && _skeleton) { @@ -74,11 +74,13 @@ void AnimClip::loadURL(const std::string& url) { } void AnimClip::setCurrentFrameInternal(float frame) { + // because dt is 0, we should not encounter any triggers const float dt = 0.0f; - _frame = accumulateTime(frame * _timeScale, dt); + Triggers triggers; + _frame = accumulateTime(frame * _timeScale, dt, triggers); } -float AnimClip::accumulateTime(float frame, float dt) const { +float AnimClip::accumulateTime(float frame, float dt, Triggers& triggersOut) const { const float startFrame = std::min(_startFrame, _endFrame); if (startFrame == _endFrame) { // when startFrame >= endFrame @@ -92,12 +94,12 @@ float AnimClip::accumulateTime(float frame, float dt) const { if (framesRemaining >= framesTillEnd) { if (_loopFlag) { // anim loop - // TODO: trigger onLoop event + triggersOut.push_back(_id + "OnLoop"); framesRemaining -= framesTillEnd; frame = startFrame; } else { // anim end - // TODO: trigger onDone event + triggersOut.push_back(_id + "OnDone"); frame = _endFrame; framesRemaining = 0.0f; } diff --git a/libraries/animation/src/AnimClip.h b/libraries/animation/src/AnimClip.h index 45924c1eed..86e6cf7733 100644 --- a/libraries/animation/src/AnimClip.h +++ b/libraries/animation/src/AnimClip.h @@ -27,7 +27,7 @@ public: AnimClip(const std::string& id, const std::string& url, float startFrame, float endFrame, float timeScale, bool loopFlag); virtual ~AnimClip() override; - virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, float dt) override; + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, float dt, Triggers& triggersOut) override; void setStartFrameVar(const std::string& startFrameVar) { _startFrameVar = startFrameVar; } void setEndFrameVar(const std::string& endFrameVar) { _endFrameVar = endFrameVar; } @@ -40,7 +40,7 @@ protected: virtual void setCurrentFrameInternal(float frame) override; - float accumulateTime(float frame, float dt) const; + float accumulateTime(float frame, float dt, Triggers& triggersOut) const; void copyFromNetworkAnim(); // for AnimDebugDraw rendering diff --git a/libraries/animation/src/AnimNode.h b/libraries/animation/src/AnimNode.h index 733428f188..06085a471a 100644 --- a/libraries/animation/src/AnimNode.h +++ b/libraries/animation/src/AnimNode.h @@ -30,6 +30,7 @@ class QJsonObject; // * hierarchy accessors, for adding, removing and iterating over child AnimNodes // * skeleton accessors, the skeleton is from the model whose bones we are going to manipulate // * evaluate method, perform actual joint manipulations here and return result by reference. +// Also, append any triggers that are detected during evaluation. class AnimNode { public: @@ -41,6 +42,7 @@ public: NumTypes }; using Pointer = std::shared_ptr; + using Triggers = std::vector; friend class AnimDebugDraw; friend void buildChildMap(std::map& map, Pointer node); @@ -76,9 +78,9 @@ public: AnimSkeleton::ConstPointer getSkeleton() const { return _skeleton; } - virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, float dt) = 0; - virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, float dt, const AnimPoseVec& underPoses) { - return evaluate(animVars, dt); + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, float dt, Triggers& triggersOut) = 0; + virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) { + return evaluate(animVars, dt, triggersOut); } protected: diff --git a/libraries/animation/src/AnimOverlay.cpp b/libraries/animation/src/AnimOverlay.cpp index 81df5811d7..dcdd9f5b4b 100644 --- a/libraries/animation/src/AnimOverlay.cpp +++ b/libraries/animation/src/AnimOverlay.cpp @@ -36,7 +36,7 @@ void AnimOverlay::buildBoneSet(BoneSet boneSet) { } } -const AnimPoseVec& AnimOverlay::evaluate(const AnimVariantMap& animVars, float dt) { +const AnimPoseVec& AnimOverlay::evaluate(const AnimVariantMap& animVars, float dt, Triggers& triggersOut) { // lookup parameters from animVars, using current instance variables as defaults. // NOTE: switching bonesets can be an expensive operation, let's try to avoid it. @@ -48,8 +48,8 @@ const AnimPoseVec& AnimOverlay::evaluate(const AnimVariantMap& animVars, float d _alpha = animVars.lookup(_alphaVar, _alpha); if (_children.size() >= 2) { - auto underPoses = _children[1]->evaluate(animVars, dt); - auto overPoses = _children[0]->overlay(animVars, dt, underPoses); + auto underPoses = _children[1]->evaluate(animVars, dt, triggersOut); + auto overPoses = _children[0]->overlay(animVars, dt, triggersOut, underPoses); if (underPoses.size() > 0 && underPoses.size() == overPoses.size()) { _poses.resize(underPoses.size()); diff --git a/libraries/animation/src/AnimOverlay.h b/libraries/animation/src/AnimOverlay.h index 5940f0b2b3..eb11510f74 100644 --- a/libraries/animation/src/AnimOverlay.h +++ b/libraries/animation/src/AnimOverlay.h @@ -40,7 +40,7 @@ public: AnimOverlay(const std::string& id, BoneSet boneSet, float alpha); virtual ~AnimOverlay() override; - virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, float dt) override; + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, float dt, Triggers& triggersOut) override; void setBoneSetVar(const std::string& boneSetVar) { _boneSetVar = boneSetVar; } void setAlphaVar(const std::string& alphaVar) { _alphaVar = alphaVar; } diff --git a/libraries/animation/src/AnimStateMachine.cpp b/libraries/animation/src/AnimStateMachine.cpp index 43bb305797..ccb3dcd91f 100644 --- a/libraries/animation/src/AnimStateMachine.cpp +++ b/libraries/animation/src/AnimStateMachine.cpp @@ -20,7 +20,7 @@ AnimStateMachine::~AnimStateMachine() { } -const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, float dt) { +const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, float dt, Triggers& triggersOut) { std::string desiredStateID = animVars.lookup(_currentStateVar, _currentState->getID()); if (_currentState->getID() != desiredStateID) { @@ -60,7 +60,7 @@ const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, fl } } if (!_duringInterp) { - _poses = currentStateNode->evaluate(animVars, dt); + _poses = currentStateNode->evaluate(animVars, dt, triggersOut); } return _poses; } @@ -88,7 +88,11 @@ void AnimStateMachine::switchState(const AnimVariantMap& animVars, State::Pointe _alphaVel = FRAMES_PER_SECOND / duration; _prevPoses = _poses; nextStateNode->setCurrentFrame(desiredState->_interpTarget); - _nextPoses = nextStateNode->evaluate(animVars, 0.0f); + + // because dt is 0, we should not encounter any triggers + const float dt = 0.0f; + Triggers triggers; + _nextPoses = nextStateNode->evaluate(animVars, dt, triggers); _currentState = desiredState; } diff --git a/libraries/animation/src/AnimStateMachine.h b/libraries/animation/src/AnimStateMachine.h index 4e9a4b3214..e48e08e96e 100644 --- a/libraries/animation/src/AnimStateMachine.h +++ b/libraries/animation/src/AnimStateMachine.h @@ -77,7 +77,7 @@ public: AnimStateMachine(const std::string& id); virtual ~AnimStateMachine() override; - virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, float dt) override; + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, float dt, Triggers& triggersOut) override; void setCurrentStateVar(std::string& currentStateVar) { _currentStateVar = currentStateVar; } diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h index 15ab7e94b1..849b6a436a 100644 --- a/libraries/animation/src/AnimVariant.h +++ b/libraries/animation/src/AnimVariant.h @@ -150,7 +150,7 @@ public: void set(const std::string& key, const std::string& value) { _map[key] = AnimVariant(value); } void setTrigger(const std::string& key) { _triggers.insert(key); } - void clearTirggers() { _triggers.clear(); } + void clearTriggers() { _triggers.clear(); } protected: std::map _map; diff --git a/tests/animation/src/data/avatar.json b/tests/animation/src/data/avatar.json index 3856588c42..5647f74a7f 100644 --- a/tests/animation/src/data/avatar.json +++ b/tests/animation/src/data/avatar.json @@ -11,11 +11,11 @@ "interpTarget": 6, "interpDuration": 6, "transitions": [ - { "var": "isMoving", "state": "walk_fwd" } + { "var": "isMoving", "state": "walkFwd" } ] }, { - "id": "walk_fwd", + "id": "walkFwd", "interpTarget": 6, "interpDuration": 6, "transitions": [ @@ -34,7 +34,7 @@ }, "children": [ { - "id": "normal_idle", + "id": "normalIdle", "type": "clip", "data": { "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/idle.fbx", @@ -46,7 +46,7 @@ "children": [] }, { - "id": "other_idle", + "id": "otherIdle", "type": "clip", "data": { "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/idle.fbx", @@ -60,7 +60,7 @@ ] }, { - "id": "walk_fwd", + "id": "walkFwd", "type": "clip", "data": { "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_fwd.fbx", @@ -72,7 +72,7 @@ "children": [] }, { - "id": "walk_bwd", + "id": "walkBwd", "type": "clip", "data": { "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_bwd.fbx", @@ -84,7 +84,7 @@ "children": [] }, { - "id": "turn_left", + "id": "turnLeft", "type": "clip", "data": { "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/turn_left.fbx", @@ -96,7 +96,7 @@ "children": [] }, { - "id": "turn_right", + "id": "turnRight", "type": "clip", "data": { "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/turn_right.fbx", @@ -108,7 +108,7 @@ "children": [] }, { - "id": "strafe_left", + "id": "strafeLeft", "type": "clip", "data": { "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/strafe_left.fbx", @@ -120,7 +120,7 @@ "children": [] }, { - "id": "strafe_right", + "id": "strafeRight", "type": "clip", "data": { "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/strafe_right.fbx",