mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-09 13:12:40 +02:00
Added support for onDone and onLoop triggers.
This commit is contained in:
parent
77b857031b
commit
9786954585
12 changed files with 50 additions and 37 deletions
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<AnimNode>;
|
||||
using Triggers = std::vector<std::string>;
|
||||
|
||||
friend class AnimDebugDraw;
|
||||
friend void buildChildMap(std::map<std::string, Pointer>& 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:
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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<std::string, AnimVariant> _map;
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue