mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 04:03:35 +02:00
AnimBlendLinear: bugfixes for sync flag added timeScale
This commit is contained in:
parent
0c36180e2f
commit
11f2d29bf8
6 changed files with 87 additions and 41 deletions
|
@ -191,6 +191,7 @@
|
||||||
"data": {
|
"data": {
|
||||||
"alpha": 0.0,
|
"alpha": 0.0,
|
||||||
"sync": false,
|
"sync": false,
|
||||||
|
"timeScale": 1.0,
|
||||||
"alphaVar": "rightHandGrabBlend"
|
"alphaVar": "rightHandGrabBlend"
|
||||||
},
|
},
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -341,6 +342,7 @@
|
||||||
"data": {
|
"data": {
|
||||||
"alpha": 0.0,
|
"alpha": 0.0,
|
||||||
"sync": false,
|
"sync": false,
|
||||||
|
"timeScale": 1.0,
|
||||||
"alphaVar": "leftHandGrabBlend"
|
"alphaVar": "leftHandGrabBlend"
|
||||||
},
|
},
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -525,16 +527,39 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "walkFwd",
|
"id": "walkFwd",
|
||||||
"type": "clip",
|
"type": "blendLinear",
|
||||||
"data": {
|
"data": {
|
||||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_fwd.fbx",
|
"alpha": 0.0,
|
||||||
"startFrame": 0.0,
|
"sync": true,
|
||||||
"endFrame": 35.0,
|
|
||||||
"timeScale": 1.0,
|
"timeScale": 1.0,
|
||||||
"loopFlag": true,
|
|
||||||
"timeScaleVar": "walkTimeScale"
|
"timeScaleVar": "walkTimeScale"
|
||||||
},
|
},
|
||||||
"children": []
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "walkFwdShort",
|
||||||
|
"type": "clip",
|
||||||
|
"data": {
|
||||||
|
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_short_fwd.fbx",
|
||||||
|
"startFrame": 0.0,
|
||||||
|
"endFrame": 39.0,
|
||||||
|
"timeScale": 1.0,
|
||||||
|
"loopFlag": true
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "walkFwdNormal",
|
||||||
|
"type": "clip",
|
||||||
|
"data": {
|
||||||
|
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_fwd.fbx",
|
||||||
|
"startFrame": 0.0,
|
||||||
|
"endFrame": 35.0,
|
||||||
|
"timeScale": 1.0,
|
||||||
|
"loopFlag": true
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "walkBwd",
|
"id": "walkBwd",
|
||||||
|
|
|
@ -14,10 +14,11 @@
|
||||||
#include "AnimUtil.h"
|
#include "AnimUtil.h"
|
||||||
#include "AnimClip.h"
|
#include "AnimClip.h"
|
||||||
|
|
||||||
AnimBlendLinear::AnimBlendLinear(const QString& id, float alpha, bool sync) :
|
AnimBlendLinear::AnimBlendLinear(const QString& id, float alpha, bool sync, float timeScale) :
|
||||||
AnimNode(AnimNode::Type::BlendLinear, id),
|
AnimNode(AnimNode::Type::BlendLinear, id),
|
||||||
_alpha(alpha),
|
_alpha(alpha),
|
||||||
_sync(sync) {
|
_sync(sync),
|
||||||
|
_timeScale(timeScale) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ AnimBlendLinear::~AnimBlendLinear() {
|
||||||
const AnimPoseVec& AnimBlendLinear::evaluate(const AnimVariantMap& animVars, float dt, Triggers& triggersOut) {
|
const AnimPoseVec& AnimBlendLinear::evaluate(const AnimVariantMap& animVars, float dt, Triggers& triggersOut) {
|
||||||
|
|
||||||
_alpha = animVars.lookup(_alphaVar, _alpha);
|
_alpha = animVars.lookup(_alphaVar, _alpha);
|
||||||
|
_timeScale = animVars.lookup(_timeScaleVar, _timeScale);
|
||||||
|
|
||||||
if (_children.size() == 0) {
|
if (_children.size() == 0) {
|
||||||
for (auto&& pose : _poses) {
|
for (auto&& pose : _poses) {
|
||||||
|
@ -42,13 +44,11 @@ const AnimPoseVec& AnimBlendLinear::evaluate(const AnimVariantMap& animVars, flo
|
||||||
size_t nextPoseIndex = glm::ceil(clampedAlpha);
|
size_t nextPoseIndex = glm::ceil(clampedAlpha);
|
||||||
float alpha = glm::fract(clampedAlpha);
|
float alpha = glm::fract(clampedAlpha);
|
||||||
|
|
||||||
float prevPoseDeltaTime = dt;
|
|
||||||
float nextPoseDeltaTime = dt;
|
|
||||||
if (_sync) {
|
if (_sync) {
|
||||||
setSyncFrameAndComputeDeltaTime(dt, prevPoseIndex, nextPoseIndex, &prevPoseDeltaTime, &nextPoseDeltaTime, triggersOut);
|
setSyncAndAccumulateTime(dt, prevPoseIndex, nextPoseIndex, triggersOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
evaluateAndBlendChildren(animVars, triggersOut, alpha, prevPoseIndex, nextPoseIndex, prevPoseDeltaTime, nextPoseDeltaTime);
|
evaluateAndBlendChildren(animVars, triggersOut, alpha, prevPoseIndex, nextPoseIndex, dt);
|
||||||
}
|
}
|
||||||
return _poses;
|
return _poses;
|
||||||
}
|
}
|
||||||
|
@ -59,15 +59,14 @@ const AnimPoseVec& AnimBlendLinear::getPosesInternal() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimBlendLinear::evaluateAndBlendChildren(const AnimVariantMap& animVars, Triggers& triggersOut, float alpha,
|
void AnimBlendLinear::evaluateAndBlendChildren(const AnimVariantMap& animVars, Triggers& triggersOut, float alpha,
|
||||||
size_t prevPoseIndex, size_t nextPoseIndex,
|
size_t prevPoseIndex, size_t nextPoseIndex, float dt) {
|
||||||
float prevPoseDeltaTime, float nextPoseDeltaTime) {
|
|
||||||
if (prevPoseIndex == nextPoseIndex) {
|
if (prevPoseIndex == nextPoseIndex) {
|
||||||
// this can happen if alpha is on an integer boundary
|
// this can happen if alpha is on an integer boundary
|
||||||
_poses = _children[prevPoseIndex]->evaluate(animVars, prevPoseDeltaTime, triggersOut);
|
_poses = _children[prevPoseIndex]->evaluate(animVars, dt, triggersOut);
|
||||||
} else {
|
} else {
|
||||||
// need to eval and blend between two children.
|
// need to eval and blend between two children.
|
||||||
auto prevPoses = _children[prevPoseIndex]->evaluate(animVars, prevPoseDeltaTime, triggersOut);
|
auto prevPoses = _children[prevPoseIndex]->evaluate(animVars, dt, triggersOut);
|
||||||
auto nextPoses = _children[nextPoseIndex]->evaluate(animVars, nextPoseDeltaTime, triggersOut);
|
auto nextPoses = _children[nextPoseIndex]->evaluate(animVars, dt, triggersOut);
|
||||||
|
|
||||||
if (prevPoses.size() > 0 && prevPoses.size() == nextPoses.size()) {
|
if (prevPoses.size() > 0 && prevPoses.size() == nextPoses.size()) {
|
||||||
_poses.resize(prevPoses.size());
|
_poses.resize(prevPoses.size());
|
||||||
|
@ -77,9 +76,7 @@ void AnimBlendLinear::evaluateAndBlendChildren(const AnimVariantMap& animVars, T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimBlendLinear::setSyncFrameAndComputeDeltaTime(float dt, size_t prevPoseIndex, size_t nextPoseIndex,
|
void AnimBlendLinear::setSyncAndAccumulateTime(float dt, size_t prevPoseIndex, size_t nextPoseIndex, Triggers& triggersOut) {
|
||||||
float* prevPoseDeltaTime, float* nextPoseDeltaTime,
|
|
||||||
Triggers& triggersOut) {
|
|
||||||
std::vector<float> offsets(_children.size(), 0.0f);
|
std::vector<float> offsets(_children.size(), 0.0f);
|
||||||
std::vector<float> timeScales(_children.size(), 1.0f);
|
std::vector<float> timeScales(_children.size(), 1.0f);
|
||||||
|
|
||||||
|
@ -88,33 +85,45 @@ void AnimBlendLinear::setSyncFrameAndComputeDeltaTime(float dt, size_t prevPoseI
|
||||||
// abort if we find a child that is NOT a clipNode.
|
// abort if we find a child that is NOT a clipNode.
|
||||||
if (_children[i]->getType() != AnimNode::Type::Clip) {
|
if (_children[i]->getType() != AnimNode::Type::Clip) {
|
||||||
// TODO: FIXME: make sync this work for other node types.
|
// TODO: FIXME: make sync this work for other node types.
|
||||||
*prevPoseDeltaTime = dt;
|
|
||||||
*nextPoseDeltaTime = dt;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto clipNode = std::dynamic_pointer_cast<AnimClip>(_children[i]);
|
auto clipNode = std::dynamic_pointer_cast<AnimClip>(_children[i]);
|
||||||
assert(clipNode);
|
assert(clipNode);
|
||||||
if (clipNode) {
|
if (clipNode) {
|
||||||
lengthSum += clipNode->getEndFrame() - clipNode->getStartFrame();
|
lengthSum += (clipNode->getEndFrame() - clipNode->getStartFrame()) + 1.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float averageLength = lengthSum / (float)_children.size();
|
_averageLength = lengthSum / (float)_children.size();
|
||||||
|
|
||||||
|
float progress = (_syncFrame / _averageLength);
|
||||||
|
|
||||||
auto prevClipNode = std::dynamic_pointer_cast<AnimClip>(_children[prevPoseIndex]);
|
auto prevClipNode = std::dynamic_pointer_cast<AnimClip>(_children[prevPoseIndex]);
|
||||||
float prevTimeScale = (prevClipNode->getEndFrame() - prevClipNode->getStartFrame()) / averageLength;
|
float prevLength = (prevClipNode->getEndFrame() - prevClipNode->getStartFrame()) + 1.0f;
|
||||||
float prevOffset = prevClipNode->getStartFrame();
|
float prevOffset = prevClipNode->getStartFrame();
|
||||||
prevClipNode->setCurrentFrame(prevOffset + prevTimeScale / _syncFrame);
|
float prevFrame = prevOffset + (progress * prevLength);
|
||||||
|
float prevTimeScale = _timeScale * (_averageLength / prevLength);
|
||||||
|
prevClipNode->setTimeScale(prevTimeScale);
|
||||||
|
prevClipNode->setCurrentFrame(prevFrame);
|
||||||
|
|
||||||
auto nextClipNode = std::dynamic_pointer_cast<AnimClip>(_children[nextPoseIndex]);
|
auto nextClipNode = std::dynamic_pointer_cast<AnimClip>(_children[nextPoseIndex]);
|
||||||
float nextTimeScale = (nextClipNode->getEndFrame() - nextClipNode->getStartFrame()) / averageLength;
|
float nextLength = (nextClipNode->getEndFrame() - nextClipNode->getStartFrame()) + 1.0f;
|
||||||
float nextOffset = nextClipNode->getStartFrame();
|
float nextOffset = nextClipNode->getStartFrame();
|
||||||
nextClipNode->setCurrentFrame(nextOffset + nextTimeScale / _syncFrame);
|
float nextFrame = nextOffset + (progress * nextLength);
|
||||||
|
float nextTimeScale = _timeScale * (_averageLength / nextLength);
|
||||||
|
nextClipNode->setTimeScale(nextTimeScale);
|
||||||
|
nextClipNode->setCurrentFrame(nextFrame);
|
||||||
|
|
||||||
|
const float START_FRAME = 0.0f;
|
||||||
const bool LOOP_FLAG = true;
|
const bool LOOP_FLAG = true;
|
||||||
_syncFrame = ::accumulateTime(0.0f, averageLength, _timeScale, _syncFrame, dt, LOOP_FLAG, _id, triggersOut);
|
_syncFrame = ::accumulateTime(START_FRAME, _averageLength, _timeScale, _syncFrame, dt, LOOP_FLAG, _id, triggersOut);
|
||||||
|
|
||||||
*prevPoseDeltaTime = prevTimeScale;
|
|
||||||
*nextPoseDeltaTime = nextTimeScale;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnimBlendLinear::setCurrentFrameInternal(float frame) {
|
||||||
|
// because dt is 0, we should not encounter any triggers
|
||||||
|
const float dt = 0.0f;
|
||||||
|
Triggers triggers;
|
||||||
|
const float START_FRAME = 0.0f;
|
||||||
|
const bool LOOP_FLAG = true;
|
||||||
|
_syncFrame = ::accumulateTime(START_FRAME, _averageLength, _timeScale, frame, dt, LOOP_FLAG, _id, triggers);
|
||||||
|
}
|
||||||
|
|
|
@ -30,32 +30,35 @@ class AnimBlendLinear : public AnimNode {
|
||||||
public:
|
public:
|
||||||
friend class AnimTests;
|
friend class AnimTests;
|
||||||
|
|
||||||
AnimBlendLinear(const QString& id, float alpha, bool sync);
|
AnimBlendLinear(const QString& id, float alpha, bool sync, float timeScale);
|
||||||
virtual ~AnimBlendLinear() override;
|
virtual ~AnimBlendLinear() override;
|
||||||
|
|
||||||
virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, float dt, Triggers& triggersOut) override;
|
virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, float dt, Triggers& triggersOut) override;
|
||||||
|
|
||||||
void setAlphaVar(const QString& alphaVar) { _alphaVar = alphaVar; }
|
void setAlphaVar(const QString& alphaVar) { _alphaVar = alphaVar; }
|
||||||
|
void setTimeScaleVar(const QString& timeScaleVar) { _timeScaleVar = timeScaleVar; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// for AnimDebugDraw rendering
|
// for AnimDebugDraw rendering
|
||||||
virtual const AnimPoseVec& getPosesInternal() const override;
|
virtual const AnimPoseVec& getPosesInternal() const override;
|
||||||
|
|
||||||
void evaluateAndBlendChildren(const AnimVariantMap& animVars, Triggers& triggersOut, float alpha,
|
void evaluateAndBlendChildren(const AnimVariantMap& animVars, Triggers& triggersOut, float alpha,
|
||||||
size_t prevPoseIndex, size_t nextPoseIndex,
|
size_t prevPoseIndex, size_t nextPoseIndex, float dt);
|
||||||
float prevPoseDeltaTime, float nextPoseDeltaTime);
|
void setSyncAndAccumulateTime(float dt, size_t prevPoseIndex, size_t nextPoseIndex, Triggers& triggersOut);
|
||||||
void setSyncFrameAndComputeDeltaTime(float dt, size_t prevPoseIndex, size_t nextPoseIndex,
|
|
||||||
float* prevPoseDeltaTime, float* nextPoseDeltaTime,
|
virtual void setCurrentFrameInternal(float frame) override;
|
||||||
Triggers& triggersOut);
|
|
||||||
|
|
||||||
AnimPoseVec _poses;
|
AnimPoseVec _poses;
|
||||||
|
|
||||||
float _alpha;
|
float _alpha;
|
||||||
bool _sync;
|
bool _sync;
|
||||||
|
float _timeScale;
|
||||||
|
|
||||||
float _syncFrame = 0.0f;
|
float _syncFrame = 0.0f;
|
||||||
float _timeScale = 1.0f; // TODO: HOOK THIS UP TO AN ANIMVAR.
|
float _averageLength = 0.0f; // average length of child animations in frames.
|
||||||
|
|
||||||
QString _alphaVar;
|
QString _alphaVar;
|
||||||
|
QString _timeScaleVar;
|
||||||
|
|
||||||
// no copies
|
// no copies
|
||||||
AnimBlendLinear(const AnimBlendLinear&) = delete;
|
AnimBlendLinear(const AnimBlendLinear&) = delete;
|
||||||
|
|
|
@ -81,7 +81,7 @@ void AnimClip::setCurrentFrameInternal(float frame) {
|
||||||
// because dt is 0, we should not encounter any triggers
|
// because dt is 0, we should not encounter any triggers
|
||||||
const float dt = 0.0f;
|
const float dt = 0.0f;
|
||||||
Triggers triggers;
|
Triggers triggers;
|
||||||
_frame = ::accumulateTime(_startFrame, _endFrame, _timeScale, frame * _timeScale, dt, _loopFlag, _id, triggers);
|
_frame = ::accumulateTime(_startFrame, _endFrame, _timeScale, frame, dt, _loopFlag, _id, triggers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimClip::copyFromNetworkAnim() {
|
void AnimClip::copyFromNetworkAnim() {
|
||||||
|
|
|
@ -39,6 +39,9 @@ public:
|
||||||
float getStartFrame() const { return _startFrame; }
|
float getStartFrame() const { return _startFrame; }
|
||||||
float getEndFrame() const { return _endFrame; }
|
float getEndFrame() const { return _endFrame; }
|
||||||
|
|
||||||
|
void setTimeScale(float timeScale) { _timeScale = timeScale; }
|
||||||
|
float getTimeScale() const { return _timeScale; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void loadURL(const QString& url);
|
void loadURL(const QString& url);
|
||||||
|
|
||||||
|
|
|
@ -225,15 +225,21 @@ static AnimNode::Pointer loadBlendLinearNode(const QJsonObject& jsonObj, const Q
|
||||||
|
|
||||||
READ_FLOAT(alpha, jsonObj, id, jsonUrl, nullptr);
|
READ_FLOAT(alpha, jsonObj, id, jsonUrl, nullptr);
|
||||||
READ_BOOL(sync, jsonObj, id, jsonUrl, nullptr);
|
READ_BOOL(sync, jsonObj, id, jsonUrl, nullptr);
|
||||||
|
READ_FLOAT(timeScale, jsonObj, id, jsonUrl, nullptr);
|
||||||
|
|
||||||
READ_OPTIONAL_STRING(alphaVar, jsonObj);
|
READ_OPTIONAL_STRING(alphaVar, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(timeScaleVar, jsonObj);
|
||||||
|
|
||||||
auto node = std::make_shared<AnimBlendLinear>(id, alpha, sync);
|
auto node = std::make_shared<AnimBlendLinear>(id, alpha, sync, timeScale);
|
||||||
|
|
||||||
if (!alphaVar.isEmpty()) {
|
if (!alphaVar.isEmpty()) {
|
||||||
node->setAlphaVar(alphaVar);
|
node->setAlphaVar(alphaVar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!timeScaleVar.isEmpty()) {
|
||||||
|
node->setTimeScaleVar(timeScaleVar);
|
||||||
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue