AddRelative blending support (Absolute is still not working)

This commit is contained in:
Anthony J. Thibault 2019-08-26 17:02:15 -07:00
parent f1afc9e873
commit ed3ba876a8
6 changed files with 76 additions and 7 deletions

View file

@ -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);
}
}
}
}

View file

@ -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;

View file

@ -34,6 +34,13 @@ enum class AnimNodeType {
NumTypes
};
enum AnimBlendType {
AnimBlendType_Normal,
AnimBlendType_AddRelative,
AnimBlendType_AddAbsolute,
AnimBlendType_NumTypes
};
class AnimContext {
public:
AnimContext() {}

View file

@ -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<AnimBlendLinear>(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<AnimBlendLinear>(id, alpha, blendTypeEnum);
if (!alphaVar.isEmpty()) {
node->setAlphaVar(alphaVar);

View file

@ -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();

View file

@ -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,