mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 18:36:45 +02:00
3x3 blend wip
This commit is contained in:
parent
ef9b81ca0d
commit
6274ab4aa7
5 changed files with 274 additions and 0 deletions
160
libraries/animation/src/AnimBlendDirectional.cpp
Normal file
160
libraries/animation/src/AnimBlendDirectional.cpp
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
//
|
||||||
|
// AnimBlendDirectional.cpp
|
||||||
|
//
|
||||||
|
// Created by Anthony J. Thibault on Augest 30 2019.
|
||||||
|
// Copyright (c) 2019 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AnimBlendDirectional.h"
|
||||||
|
#include "GLMHelpers.h"
|
||||||
|
#include "AnimationLogging.h"
|
||||||
|
#include "AnimUtil.h"
|
||||||
|
|
||||||
|
AnimBlendDirectional::AnimBlendDirectional(const QString& id, float alpha, const QString& centerId,
|
||||||
|
const QString& upId, const QString& downId, const QString& leftId, const QString& rightId,
|
||||||
|
const QString& upLeftId, const QString& upRightId, const QString& downLeftId, const QString& downRightId) :
|
||||||
|
AnimNode(AnimNode::Type::BlendDirectional, id),
|
||||||
|
_alpha(alpha),
|
||||||
|
_upId(upId),
|
||||||
|
_downId(downId),
|
||||||
|
_leftId(leftId),
|
||||||
|
_rightId(rightId),
|
||||||
|
_upLeftId(upLeftId),
|
||||||
|
_upRightId(upRightId),
|
||||||
|
_downLeftId(downLeftId),
|
||||||
|
_downRightId(downRightId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimBlendDirectional::~AnimBlendDirectional() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const AnimPoseVec& AnimBlendDirectional::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) {
|
||||||
|
|
||||||
|
_alpha = animVars.lookup(_alphaVar, _alpha);
|
||||||
|
float parentDebugAlpha = context.getDebugAlpha(_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (_children.size() == 0) {
|
||||||
|
for (auto&& pose : _poses) {
|
||||||
|
pose = AnimPose::identity;
|
||||||
|
}
|
||||||
|
} else if (_children.size() == 1) {
|
||||||
|
_poses = _children[0]->evaluate(animVars, context, dt, triggersOut);
|
||||||
|
context.setDebugAlpha(_children[0]->getID(), parentDebugAlpha, _children[0]->getType());
|
||||||
|
} else if (_children.size() == 2 && _blendType != AnimBlendType_Normal) {
|
||||||
|
// special case for additive blending
|
||||||
|
float alpha = glm::clamp(_alpha, 0.0f, 1.0f);
|
||||||
|
const size_t prevPoseIndex = 0;
|
||||||
|
const size_t nextPoseIndex = 1;
|
||||||
|
evaluateAndBlendChildren(animVars, context, triggersOut, alpha, prevPoseIndex, nextPoseIndex, dt);
|
||||||
|
|
||||||
|
// for animation stack debugging
|
||||||
|
float weight2 = alpha;
|
||||||
|
float weight1 = 1.0f - weight2;
|
||||||
|
context.setDebugAlpha(_children[prevPoseIndex]->getID(), weight1 * parentDebugAlpha, _children[prevPoseIndex]->getType());
|
||||||
|
context.setDebugAlpha(_children[nextPoseIndex]->getID(), weight2 * parentDebugAlpha, _children[nextPoseIndex]->getType());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
float clampedAlpha = glm::clamp(_alpha, 0.0f, (float)(_children.size() - 1));
|
||||||
|
size_t prevPoseIndex = glm::floor(clampedAlpha);
|
||||||
|
size_t nextPoseIndex = glm::ceil(clampedAlpha);
|
||||||
|
auto alpha = glm::fract(clampedAlpha);
|
||||||
|
evaluateAndBlendChildren(animVars, context, triggersOut, alpha, prevPoseIndex, nextPoseIndex, dt);
|
||||||
|
|
||||||
|
// weights are for animation stack debug purposes only.
|
||||||
|
float weight1 = 0.0f;
|
||||||
|
float weight2 = 0.0f;
|
||||||
|
if (prevPoseIndex == nextPoseIndex) {
|
||||||
|
weight2 = 1.0f;
|
||||||
|
context.setDebugAlpha(_children[nextPoseIndex]->getID(), weight2 * parentDebugAlpha, _children[nextPoseIndex]->getType());
|
||||||
|
} else {
|
||||||
|
weight2 = alpha;
|
||||||
|
weight1 = 1.0f - weight2;
|
||||||
|
context.setDebugAlpha(_children[prevPoseIndex]->getID(), weight1 * parentDebugAlpha, _children[prevPoseIndex]->getType());
|
||||||
|
context.setDebugAlpha(_children[nextPoseIndex]->getID(), weight2 * parentDebugAlpha, _children[nextPoseIndex]->getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processOutputJoints(triggersOut);
|
||||||
|
*/
|
||||||
|
|
||||||
|
return _poses;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for AnimDebugDraw rendering
|
||||||
|
const AnimPoseVec& AnimBlendDirectional::getPosesInternal() const {
|
||||||
|
return _poses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void AnimBlendDirectional::evaluateAndBlendChildren(const AnimVariantMap& animVars, const AnimContext& context, AnimVariantMap& triggersOut, float alpha,
|
||||||
|
size_t prevPoseIndex, size_t nextPoseIndex, float dt) {
|
||||||
|
if (prevPoseIndex == nextPoseIndex) {
|
||||||
|
// this can happen if alpha is on an integer boundary
|
||||||
|
_poses = _children[prevPoseIndex]->evaluate(animVars, context, dt, triggersOut);
|
||||||
|
} else {
|
||||||
|
// need to eval and blend between two children.
|
||||||
|
auto prevPoses = _children[prevPoseIndex]->evaluate(animVars, context, dt, triggersOut);
|
||||||
|
auto nextPoses = _children[nextPoseIndex]->evaluate(animVars, context, dt, triggersOut);
|
||||||
|
|
||||||
|
if (prevPoses.size() > 0 && prevPoses.size() == nextPoses.size()) {
|
||||||
|
_poses.resize(prevPoses.size());
|
||||||
|
|
||||||
|
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) {
|
||||||
|
// convert prev from relative to absolute
|
||||||
|
AnimPoseVec absPrev = prevPoses;
|
||||||
|
_skeleton->convertRelativePosesToAbsolute(absPrev);
|
||||||
|
|
||||||
|
// rotate the offset rotations from next into the parent relative frame of each joint.
|
||||||
|
AnimPoseVec relOffsetPoses;
|
||||||
|
relOffsetPoses.reserve(nextPoses.size());
|
||||||
|
for (size_t i = 0; i < nextPoses.size(); ++i) {
|
||||||
|
|
||||||
|
// copy translation and scale from nextPoses
|
||||||
|
AnimPose pose = nextPoses[i];
|
||||||
|
|
||||||
|
int parentIndex = _skeleton->getParentIndex((int)i);
|
||||||
|
if (parentIndex >= 0) {
|
||||||
|
// but transform nextPoses rot into absPrev parent frame.
|
||||||
|
pose.rot() = glm::inverse(absPrev[parentIndex].rot()) * pose.rot() * absPrev[parentIndex].rot();
|
||||||
|
}
|
||||||
|
|
||||||
|
relOffsetPoses.push_back(pose);
|
||||||
|
}
|
||||||
|
|
||||||
|
// then blend
|
||||||
|
::blendAdd(_poses.size(), &prevPoses[0], &relOffsetPoses[0], alpha, &_poses[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool AnimBlendDirectional::lookupChildIds() {
|
||||||
|
_center = findChildIndexByName(_centerId);
|
||||||
|
_up = findChildIndexByName(_upId);
|
||||||
|
_down = findChildIndexByName(_downId);
|
||||||
|
_left = findChildIndexByName(_leftId);
|
||||||
|
_right = findChildIndexByName(_rightId);
|
||||||
|
_upLeft = findChildIndexByName(_upLeftId);
|
||||||
|
_upRight = findChildIndexByName(_upRightId);
|
||||||
|
_downLeft = findChildIndexByName(_downLeftId);
|
||||||
|
_downRight = findChildIndexByName(_downRightId);
|
||||||
|
|
||||||
|
// manditory children
|
||||||
|
// TODO: currently all are manditory.
|
||||||
|
if (_center == -1 || _up == -1 || _down == -1 || _left == -1 || _right== -1 ||
|
||||||
|
_upLeft == -1 || _upRight == -1 || _downLeft == -1 || _downRight == -1) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
67
libraries/animation/src/AnimBlendDirectional.h
Normal file
67
libraries/animation/src/AnimBlendDirectional.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
//
|
||||||
|
// AnimBlendDirectonal.h
|
||||||
|
//
|
||||||
|
// Created by Anthony J. Thibault on Augest 30 2019.
|
||||||
|
// Copyright (c) 2019 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_AnimBlendDirectional_h
|
||||||
|
#define hifi_AnimBlendDirectional_h
|
||||||
|
|
||||||
|
#include "AnimNode.h"
|
||||||
|
|
||||||
|
// blend between up to nine AnimNodes.
|
||||||
|
|
||||||
|
class AnimBlendDirectional : public AnimNode {
|
||||||
|
public:
|
||||||
|
friend class AnimTests;
|
||||||
|
|
||||||
|
AnimBlendDirectional(const QString& id, float alpha, const QString& centerId,
|
||||||
|
const QString& upId, const QString& downId, const QString& leftId, const QString& rightId,
|
||||||
|
const QString& upLeftId, const QString& upRightId, const QString& downLeftId, const QString& downRightId);
|
||||||
|
virtual ~AnimBlendDirectional() override;
|
||||||
|
|
||||||
|
virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override;
|
||||||
|
|
||||||
|
void setAlphaVar(const QString& alphaVar) { _alphaVar = alphaVar; }
|
||||||
|
|
||||||
|
bool lookupChildIds();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// for AnimDebugDraw rendering
|
||||||
|
virtual const AnimPoseVec& getPosesInternal() const override;
|
||||||
|
|
||||||
|
AnimPoseVec _poses;
|
||||||
|
|
||||||
|
float _alpha;
|
||||||
|
QString _centerId;
|
||||||
|
QString _upId;
|
||||||
|
QString _downId;
|
||||||
|
QString _leftId;
|
||||||
|
QString _rightId;
|
||||||
|
QString _upLeftId;
|
||||||
|
QString _upRightId;
|
||||||
|
QString _downLeftId;
|
||||||
|
QString _downRightId;
|
||||||
|
|
||||||
|
QString _alphaVar;
|
||||||
|
|
||||||
|
int _center;
|
||||||
|
int _up;
|
||||||
|
int _down;
|
||||||
|
int _left;
|
||||||
|
int _right;
|
||||||
|
int _upLeft;
|
||||||
|
int _upRight;
|
||||||
|
int _downLeft;
|
||||||
|
int _downRight;
|
||||||
|
|
||||||
|
// no copies
|
||||||
|
AnimBlendDirectional(const AnimBlendDirectional&) = delete;
|
||||||
|
AnimBlendDirectional& operator=(const AnimBlendDirectional&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_AnimBlendDirectional_h
|
|
@ -31,6 +31,7 @@ enum class AnimNodeType {
|
||||||
TwoBoneIK,
|
TwoBoneIK,
|
||||||
SplineIK,
|
SplineIK,
|
||||||
PoleVectorConstraint,
|
PoleVectorConstraint,
|
||||||
|
BlendDirectional,
|
||||||
NumTypes
|
NumTypes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,15 @@ public:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int findChildIndexByName(const QString& id) {
|
||||||
|
for (int i = 0; i < _children.size(); ++i) {
|
||||||
|
if (_children[i]->getID() == id) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
const AnimPoseVec& getPoses() const { return getPosesInternal(); }
|
const AnimPoseVec& getPoses() const { return getPosesInternal(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "AnimTwoBoneIK.h"
|
#include "AnimTwoBoneIK.h"
|
||||||
#include "AnimSplineIK.h"
|
#include "AnimSplineIK.h"
|
||||||
#include "AnimPoleVectorConstraint.h"
|
#include "AnimPoleVectorConstraint.h"
|
||||||
|
#include "AnimBlendDirectional.h"
|
||||||
#include "AnimUtil.h"
|
#include "AnimUtil.h"
|
||||||
|
|
||||||
using NodeLoaderFunc = AnimNode::Pointer (*)(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
using NodeLoaderFunc = AnimNode::Pointer (*)(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
|
@ -47,6 +48,7 @@ static AnimNode::Pointer loadDefaultPoseNode(const QJsonObject& jsonObj, const Q
|
||||||
static AnimNode::Pointer loadTwoBoneIKNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
static AnimNode::Pointer loadTwoBoneIKNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
static AnimNode::Pointer loadSplineIKNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
static AnimNode::Pointer loadSplineIKNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
static AnimNode::Pointer loadPoleVectorConstraintNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
static AnimNode::Pointer loadPoleVectorConstraintNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
|
static AnimNode::Pointer loadBlendDirectionalNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
|
|
||||||
static const float ANIM_GRAPH_LOAD_PRIORITY = 10.0f;
|
static const float ANIM_GRAPH_LOAD_PRIORITY = 10.0f;
|
||||||
|
|
||||||
|
@ -55,6 +57,7 @@ static const float ANIM_GRAPH_LOAD_PRIORITY = 10.0f;
|
||||||
static bool processDoNothing(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) { return true; }
|
static bool processDoNothing(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) { return true; }
|
||||||
bool processStateMachineNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
bool processStateMachineNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
bool processRandomSwitchStateMachineNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
bool processRandomSwitchStateMachineNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
|
bool processBlendDirectionalNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
|
|
||||||
static const char* animNodeTypeToString(AnimNode::Type type) {
|
static const char* animNodeTypeToString(AnimNode::Type type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -70,6 +73,7 @@ static const char* animNodeTypeToString(AnimNode::Type type) {
|
||||||
case AnimNode::Type::TwoBoneIK: return "twoBoneIK";
|
case AnimNode::Type::TwoBoneIK: return "twoBoneIK";
|
||||||
case AnimNode::Type::SplineIK: return "splineIK";
|
case AnimNode::Type::SplineIK: return "splineIK";
|
||||||
case AnimNode::Type::PoleVectorConstraint: return "poleVectorConstraint";
|
case AnimNode::Type::PoleVectorConstraint: return "poleVectorConstraint";
|
||||||
|
case AnimNode::Type::BlendDirectional: return "blendDirectional";
|
||||||
case AnimNode::Type::NumTypes: return nullptr;
|
case AnimNode::Type::NumTypes: return nullptr;
|
||||||
};
|
};
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -211,6 +215,7 @@ static NodeLoaderFunc animNodeTypeToLoaderFunc(AnimNode::Type type) {
|
||||||
case AnimNode::Type::TwoBoneIK: return loadTwoBoneIKNode;
|
case AnimNode::Type::TwoBoneIK: return loadTwoBoneIKNode;
|
||||||
case AnimNode::Type::SplineIK: return loadSplineIKNode;
|
case AnimNode::Type::SplineIK: return loadSplineIKNode;
|
||||||
case AnimNode::Type::PoleVectorConstraint: return loadPoleVectorConstraintNode;
|
case AnimNode::Type::PoleVectorConstraint: return loadPoleVectorConstraintNode;
|
||||||
|
case AnimNode::Type::BlendDirectional: return loadBlendDirectionalNode;
|
||||||
case AnimNode::Type::NumTypes: return nullptr;
|
case AnimNode::Type::NumTypes: return nullptr;
|
||||||
};
|
};
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -230,6 +235,7 @@ static NodeProcessFunc animNodeTypeToProcessFunc(AnimNode::Type type) {
|
||||||
case AnimNode::Type::TwoBoneIK: return processDoNothing;
|
case AnimNode::Type::TwoBoneIK: return processDoNothing;
|
||||||
case AnimNode::Type::SplineIK: return processDoNothing;
|
case AnimNode::Type::SplineIK: return processDoNothing;
|
||||||
case AnimNode::Type::PoleVectorConstraint: return processDoNothing;
|
case AnimNode::Type::PoleVectorConstraint: return processDoNothing;
|
||||||
|
case AnimNode::Type::BlendDirectional: return processBlendDirectionalNode;
|
||||||
case AnimNode::Type::NumTypes: return nullptr;
|
case AnimNode::Type::NumTypes: return nullptr;
|
||||||
};
|
};
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -772,6 +778,32 @@ static AnimNode::Pointer loadPoleVectorConstraintNode(const QJsonObject& jsonObj
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AnimNode::Pointer loadBlendDirectionalNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) {
|
||||||
|
|
||||||
|
READ_FLOAT(alpha, jsonObj, id, jsonUrl, nullptr);
|
||||||
|
READ_OPTIONAL_STRING(alphaVar, jsonObj);
|
||||||
|
|
||||||
|
READ_OPTIONAL_STRING(centerId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(upId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(downId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(leftId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(rightId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(upLeftId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(upRightId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(downLeftId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(downRightId, jsonObj);
|
||||||
|
|
||||||
|
auto node = std::make_shared<AnimBlendDirectional>(id, alpha, centerId,
|
||||||
|
upId, downId, leftId, rightId,
|
||||||
|
upLeftId, upRightId, downLeftId, downRightId);
|
||||||
|
|
||||||
|
if (!alphaVar.isEmpty()) {
|
||||||
|
node->setAlphaVar(alphaVar);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
void buildChildMap(std::map<QString, int>& map, AnimNode::Pointer node) {
|
void buildChildMap(std::map<QString, int>& map, AnimNode::Pointer node) {
|
||||||
for (int i = 0; i < (int)node->getChildCount(); ++i) {
|
for (int i = 0; i < (int)node->getChildCount(); ++i) {
|
||||||
map.insert(std::pair<QString, int>(node->getChild(i)->getID(), i));
|
map.insert(std::pair<QString, int>(node->getChild(i)->getID(), i));
|
||||||
|
@ -1042,7 +1074,12 @@ bool processRandomSwitchStateMachineNode(AnimNode::Pointer node, const QJsonObje
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool processBlendDirectionalNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& nodeId, const QUrl& jsonUrl) {
|
||||||
|
auto blendNode = std::static_pointer_cast<AnimBlendDirectional>(node);
|
||||||
|
assert(blendNode);
|
||||||
|
|
||||||
|
return blendNode->lookupChildIds();
|
||||||
|
}
|
||||||
|
|
||||||
AnimNodeLoader::AnimNodeLoader(const QUrl& url) :
|
AnimNodeLoader::AnimNodeLoader(const QUrl& url) :
|
||||||
_url(url)
|
_url(url)
|
||||||
|
|
Loading…
Reference in a new issue