From ed3ba876a840f2e670e209e41798b5fdf9e1957e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 26 Aug 2019 17:02:15 -0700 Subject: [PATCH] AddRelative blending support (Absolute is still not working) --- libraries/animation/src/AnimBlendLinear.cpp | 23 +++++++++++++++--- libraries/animation/src/AnimBlendLinear.h | 3 ++- libraries/animation/src/AnimContext.h | 7 ++++++ libraries/animation/src/AnimNodeLoader.cpp | 26 +++++++++++++++++++-- libraries/animation/src/AnimUtil.cpp | 21 ++++++++++++++++- libraries/animation/src/AnimUtil.h | 3 +++ 6 files changed, 76 insertions(+), 7 deletions(-) diff --git a/libraries/animation/src/AnimBlendLinear.cpp b/libraries/animation/src/AnimBlendLinear.cpp index 17ca88123f..c740de72cb 100644 --- a/libraries/animation/src/AnimBlendLinear.cpp +++ b/libraries/animation/src/AnimBlendLinear.cpp @@ -14,9 +14,10 @@ #include "AnimUtil.h" #include "AnimClip.h" -AnimBlendLinear::AnimBlendLinear(const QString& id, float alpha) : +AnimBlendLinear::AnimBlendLinear(const QString& id, float alpha, AnimBlendType blendType) : AnimNode(AnimNode::Type::BlendLinear, id), - _alpha(alpha) { + _alpha(alpha), + _blendType(blendType) { } @@ -79,7 +80,23 @@ void AnimBlendLinear::evaluateAndBlendChildren(const AnimVariantMap& animVars, c if (prevPoses.size() > 0 && prevPoses.size() == nextPoses.size()) { _poses.resize(prevPoses.size()); - ::blend(_poses.size(), &prevPoses[0], &nextPoses[0], alpha, &_poses[0]); + if (_blendType == AnimBlendType_Normal) { + ::blend(_poses.size(), &prevPoses[0], &nextPoses[0], alpha, &_poses[0]); + } else if (_blendType == AnimBlendType_AddRelative) { + ::blendAdd(_poses.size(), &prevPoses[0], &nextPoses[0], alpha, &_poses[0]); + } else if (_blendType == AnimBlendType_AddAbsolute) { + // onvert from relative to absolute + AnimPoseVec prev = prevPoses; + _skeleton->convertRelativePosesToAbsolute(prev); + AnimPoseVec next = nextPoses; + _skeleton->convertRelativePosesToAbsolute(next); + + // then blend + ::blendAdd(_poses.size(), &prevPoses[0], &nextPoses[0], alpha, &_poses[0]); + + // convert result back into relative + _skeleton->convertAbsolutePosesToRelative(_poses); + } } } } diff --git a/libraries/animation/src/AnimBlendLinear.h b/libraries/animation/src/AnimBlendLinear.h index d0fe2a8503..e6fb39438f 100644 --- a/libraries/animation/src/AnimBlendLinear.h +++ b/libraries/animation/src/AnimBlendLinear.h @@ -27,7 +27,7 @@ class AnimBlendLinear : public AnimNode { public: friend class AnimTests; - AnimBlendLinear(const QString& id, float alpha); + AnimBlendLinear(const QString& id, float alpha, AnimBlendType blendType); virtual ~AnimBlendLinear() override; virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override; @@ -43,6 +43,7 @@ protected: AnimPoseVec _poses; + AnimBlendType _blendType; float _alpha; QString _alphaVar; diff --git a/libraries/animation/src/AnimContext.h b/libraries/animation/src/AnimContext.h index 5f353fcae4..2ee8a30980 100644 --- a/libraries/animation/src/AnimContext.h +++ b/libraries/animation/src/AnimContext.h @@ -34,6 +34,13 @@ enum class AnimNodeType { NumTypes }; +enum AnimBlendType { + AnimBlendType_Normal, + AnimBlendType_AddRelative, + AnimBlendType_AddAbsolute, + AnimBlendType_NumTypes +}; + class AnimContext { public: AnimContext() {} diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp index ebd8a6de5b..c00dabfb5d 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -161,6 +161,19 @@ static EasingType stringToEasingType(const QString& str) { } } +static AnimBlendType stringToAnimBlendType(const QString& str) { + if (str == "normal") { + return AnimBlendType_Normal; + } else if (str == "addRelative") { + return AnimBlendType_AddRelative; + } else if (str == "addAbsolute") { + return AnimBlendType_AddAbsolute; + } else { + return AnimBlendType_NumTypes; + } +} + + static const char* animManipulatorJointVarTypeToString(AnimManipulator::JointVar::Type type) { switch (type) { case AnimManipulator::JointVar::Type::Absolute: return "absolute"; @@ -413,10 +426,19 @@ static AnimNode::Pointer loadClipNode(const QJsonObject& jsonObj, const QString& static AnimNode::Pointer loadBlendLinearNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) { READ_FLOAT(alpha, jsonObj, id, jsonUrl, nullptr); - + READ_OPTIONAL_STRING(blendType, jsonObj); READ_OPTIONAL_STRING(alphaVar, jsonObj); - auto node = std::make_shared(id, alpha); + AnimBlendType blendTypeEnum = AnimBlendType_Normal; // default value + if (!blendType.isEmpty()) { + blendTypeEnum = stringToAnimBlendType(blendType); + if (blendTypeEnum == AnimBlendType_NumTypes) { + qCCritical(animation) << "AnimNodeLoader, bad blendType on blendLinear, id = " << id; + return nullptr; + } + } + + auto node = std::make_shared(id, alpha, blendTypeEnum); if (!alphaVar.isEmpty()) { node->setAlphaVar(alphaVar); diff --git a/libraries/animation/src/AnimUtil.cpp b/libraries/animation/src/AnimUtil.cpp index f4f922d704..621e714f97 100644 --- a/libraries/animation/src/AnimUtil.cpp +++ b/libraries/animation/src/AnimUtil.cpp @@ -15,7 +15,6 @@ // TODO: use restrict keyword // TODO: excellent candidate for simd vectorization. - void blend(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result) { for (size_t i = 0; i < numPoses; i++) { const AnimPose& aPose = a[i]; @@ -27,6 +26,26 @@ void blend(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, A } } +// additive blend +void blendAdd(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result) { + for (size_t i = 0; i < numPoses; i++) { + const AnimPose& aPose = a[i]; + const AnimPose& bPose = b[i]; + + result[i].scale() = lerp(aPose.scale(), bPose.scale(), alpha); + + // adjust sign of bPose.rot() if necessary + glm::quat bTemp = bPose.rot(); + float dot = glm::dot(aPose.rot(), bTemp); + if (dot < 0.0f) { + bTemp = -bTemp; + } + result[i].rot() = glm::normalize((alpha * bTemp) * aPose.rot()); + + result[i].trans() = aPose.trans() + (alpha * bPose.trans()); + } +} + glm::quat averageQuats(size_t numQuats, const glm::quat* quats) { if (numQuats == 0) { return glm::quat(); diff --git a/libraries/animation/src/AnimUtil.h b/libraries/animation/src/AnimUtil.h index 26dc19da06..5d67b27abb 100644 --- a/libraries/animation/src/AnimUtil.h +++ b/libraries/animation/src/AnimUtil.h @@ -16,6 +16,9 @@ // this is where the magic happens void blend(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result); +// additive blending +void blendAdd(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result); + glm::quat averageQuats(size_t numQuats, const glm::quat* quats); float accumulateTime(float startFrame, float endFrame, float timeScale, float currentFrame, float dt, bool loopFlag,