Added basic interpolation support to AnimStateMachine

This commit is contained in:
Anthony J. Thibault 2015-08-27 21:26:31 -07:00
parent 3286a32afc
commit 19e91bb392
7 changed files with 42 additions and 28 deletions

View file

@ -1245,7 +1245,7 @@ void MyAvatar::setupNewAnimationSystem() {
// load the anim graph // load the anim graph
// https://gist.github.com/hyperlogic/7d6a0892a7319c69e2b9 // https://gist.github.com/hyperlogic/7d6a0892a7319c69e2b9
auto graphUrl = QUrl("https://gist.githubusercontent.com/hyperlogic/7d6a0892a7319c69e2b9/raw/c684000794675bc84ed63efefc21870e47c58d6a/avatar.json"); auto graphUrl = QUrl("https://gist.githubusercontent.com/hyperlogic/7d6a0892a7319c69e2b9/raw/250ce1f207e23c74694351f04367063cf1269f94/avatar.json");
_animLoader.reset(new AnimNodeLoader(graphUrl)); _animLoader.reset(new AnimNodeLoader(graphUrl));
connect(_animLoader.get(), &AnimNodeLoader::success, [this](AnimNode::Pointer nodeIn) { connect(_animLoader.get(), &AnimNodeLoader::success, [this](AnimNode::Pointer nodeIn) {
_animNode = nodeIn; _animNode = nodeIn;

View file

@ -48,7 +48,7 @@ const AnimPoseVec& AnimBlendLinear::evaluate(const AnimVariantMap& animVars, flo
if (prevPoses.size() > 0 && prevPoses.size() == nextPoses.size()) { if (prevPoses.size() > 0 && prevPoses.size() == nextPoses.size()) {
_poses.resize(prevPoses.size()); _poses.resize(prevPoses.size());
blend(_poses.size(), &prevPoses[0], &nextPoses[0], alpha, &_poses[0]); ::blend(_poses.size(), &prevPoses[0], &nextPoses[0], alpha, &_poses[0]);
} }
} }
} }

View file

@ -61,7 +61,7 @@ const AnimPoseVec& AnimClip::evaluate(const AnimVariantMap& animVars, float dt)
const AnimPoseVec& nextFrame = _anim[nextIndex]; const AnimPoseVec& nextFrame = _anim[nextIndex];
float alpha = glm::fract(_frame); float alpha = glm::fract(_frame);
blend(_poses.size(), &prevFrame[0], &nextFrame[0], alpha, &_poses[0]); ::blend(_poses.size(), &prevFrame[0], &nextFrame[0], alpha, &_poses[0]);
} }
return _poses; return _poses;

View file

@ -44,6 +44,7 @@ public:
friend class AnimDebugDraw; friend class AnimDebugDraw;
friend void buildChildMap(std::map<std::string, Pointer>& map, Pointer node); friend void buildChildMap(std::map<std::string, Pointer>& map, Pointer node);
friend class AnimStateMachine;
AnimNode(Type type, const std::string& id) : _type(type), _id(id) {} AnimNode(Type type, const std::string& id) : _type(type), _id(id) {}
virtual ~AnimNode() {} virtual ~AnimNode() {}

View file

@ -57,7 +57,7 @@ const AnimPoseVec& AnimOverlay::evaluate(const AnimVariantMap& animVars, float d
for (size_t i = 0; i < _poses.size(); i++) { for (size_t i = 0; i < _poses.size(); i++) {
float alpha = _boneSetVec[i] * _alpha; float alpha = _boneSetVec[i] * _alpha;
blend(1, &underPoses[i], &overPoses[i], alpha, &_poses[i]); ::blend(1, &underPoses[i], &overPoses[i], alpha, &_poses[i]);
} }
} }
} }

View file

@ -8,6 +8,7 @@
// //
#include "AnimStateMachine.h" #include "AnimStateMachine.h"
#include "AnimUtil.h"
#include "AnimationLogging.h" #include "AnimationLogging.h"
AnimStateMachine::AnimStateMachine(const std::string& id) : AnimStateMachine::AnimStateMachine(const std::string& id) :
@ -19,8 +20,6 @@ AnimStateMachine::~AnimStateMachine() {
} }
const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, float dt) { const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, float dt) {
std::string desiredStateID = animVars.lookup(_currentStateVar, _currentState->getID()); std::string desiredStateID = animVars.lookup(_currentStateVar, _currentState->getID());
@ -29,7 +28,7 @@ const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, fl
bool foundState = false; bool foundState = false;
for (auto& state : _states) { for (auto& state : _states) {
if (state->getID() == desiredStateID) { if (state->getID() == desiredStateID) {
switchState(state); switchState(animVars, state);
foundState = true; foundState = true;
break; break;
} }
@ -42,26 +41,27 @@ const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, fl
// evaluate currentState transitions // evaluate currentState transitions
auto desiredState = evaluateTransitions(animVars); auto desiredState = evaluateTransitions(animVars);
if (desiredState != _currentState) { if (desiredState != _currentState) {
switchState(desiredState); switchState(animVars, desiredState);
} }
if (_duringInterp) {
// TODO: do interpolation
/*
const float FRAMES_PER_SECOND = 30.0f;
// blend betwen poses
blend(_poses.size(), _prevPose, _nextPose, _alpha, &_poses[0]);
*/
} else {
// eval current state
assert(_currentState); assert(_currentState);
auto currentStateNode = _currentState->getNode(); auto currentStateNode = _currentState->getNode();
assert(currentStateNode); assert(currentStateNode);
if (_duringInterp) {
_alpha += _alphaVel * dt;
if (_alpha < 1.0f) {
::blend(_poses.size(), &_prevPoses[0], &_nextPoses[0], _alpha, &_poses[0]);
} else {
_duringInterp = false;
_prevPoses.clear();
_nextPoses.clear();
}
}
if (!_duringInterp) {
_poses = currentStateNode->evaluate(animVars, dt); _poses = currentStateNode->evaluate(animVars, dt);
} }
qCDebug(animation) << "StateMachine::evalute";
return _poses; return _poses;
} }
@ -73,9 +73,23 @@ void AnimStateMachine::addState(State::Pointer state) {
_states.push_back(state); _states.push_back(state);
} }
void AnimStateMachine::switchState(State::Pointer desiredState) { void AnimStateMachine::switchState(const AnimVariantMap& animVars, State::Pointer desiredState) {
qCDebug(animation) << "AnimStateMachine::switchState:" << _currentState->getID().c_str() << "->" << desiredState->getID().c_str(); qCDebug(animation) << "AnimStateMachine::switchState:" << _currentState->getID().c_str() << "->" << desiredState->getID().c_str();
// TODO: interp.
const float FRAMES_PER_SECOND = 30.0f;
auto prevStateNode = _currentState->getNode();
auto nextStateNode = desiredState->getNode();
_duringInterp = true;
_alpha = 0.0f;
float duration = std::max(0.001f, animVars.lookup(desiredState->_interpDurationVar, desiredState->_interpDuration));
_alphaVel = FRAMES_PER_SECOND / duration;
_prevPoses = _poses;
nextStateNode->setCurrentFrame(desiredState->_interpTarget);
_nextPoses = nextStateNode->evaluate(animVars, 0.0f);
_currentState = desiredState; _currentState = desiredState;
} }

View file

@ -87,7 +87,7 @@ protected:
void addState(State::Pointer state); void addState(State::Pointer state);
void switchState(State::Pointer desiredState); void switchState(const AnimVariantMap& animVars, State::Pointer desiredState);
State::Pointer evaluateTransitions(const AnimVariantMap& animVars) const; State::Pointer evaluateTransitions(const AnimVariantMap& animVars) const;
// for AnimDebugDraw rendering // for AnimDebugDraw rendering
@ -97,9 +97,8 @@ protected:
// interpolation state // interpolation state
bool _duringInterp = false; bool _duringInterp = false;
float _interpFrame; float _alphaVel = 0.0f;
float _interpDuration; float _alpha = 0.0f;
float _alpha;
AnimPoseVec _prevPoses; AnimPoseVec _prevPoses;
AnimPoseVec _nextPoses; AnimPoseVec _nextPoses;