mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 07:58:59 +02:00
Added AnimOverlay node, moved blend sub-routine into AnimUtil.
This commit is contained in:
parent
2d0315978e
commit
1f8c8adbd6
8 changed files with 185 additions and 16 deletions
|
@ -10,6 +10,7 @@
|
||||||
#include "AnimBlendLinear.h"
|
#include "AnimBlendLinear.h"
|
||||||
#include "GLMHelpers.h"
|
#include "GLMHelpers.h"
|
||||||
#include "AnimationLogging.h"
|
#include "AnimationLogging.h"
|
||||||
|
#include "AnimUtil.h"
|
||||||
|
|
||||||
AnimBlendLinear::AnimBlendLinear(const std::string& id, float alpha) :
|
AnimBlendLinear::AnimBlendLinear(const std::string& id, float alpha) :
|
||||||
AnimNode(AnimNode::BlendLinearType, id),
|
AnimNode(AnimNode::BlendLinearType, id),
|
||||||
|
@ -40,13 +41,8 @@ const std::vector<AnimPose>& AnimBlendLinear::evaluate(float dt) {
|
||||||
|
|
||||||
if (prevPoses.size() > 0 && prevPoses.size() == nextPoses.size()) {
|
if (prevPoses.size() > 0 && prevPoses.size() == nextPoses.size()) {
|
||||||
_poses.resize(prevPoses.size());
|
_poses.resize(prevPoses.size());
|
||||||
for (size_t i = 0; i < _poses.size(); i++) {
|
|
||||||
const AnimPose& prevPose = prevPoses[i];
|
blend(_poses.size(), &prevPoses[0], &nextPoses[0], alpha, &_poses[0]);
|
||||||
const AnimPose& nextPose = nextPoses[i];
|
|
||||||
_poses[i].scale = lerp(prevPose.scale, nextPose.scale, alpha);
|
|
||||||
_poses[i].rot = glm::normalize(glm::lerp(prevPose.rot, nextPose.rot, alpha));
|
|
||||||
_poses[i].trans = lerp(prevPose.trans, nextPose.trans, alpha);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "GLMHelpers.h"
|
#include "GLMHelpers.h"
|
||||||
#include "AnimClip.h"
|
#include "AnimClip.h"
|
||||||
#include "AnimationLogging.h"
|
#include "AnimationLogging.h"
|
||||||
|
#include "AnimUtil.h"
|
||||||
|
|
||||||
AnimClip::AnimClip(const std::string& id, const std::string& url, float startFrame, float endFrame, float timeScale, bool loopFlag) :
|
AnimClip::AnimClip(const std::string& id, const std::string& url, float startFrame, float endFrame, float timeScale, bool loopFlag) :
|
||||||
AnimNode(AnimNode::ClipType, id),
|
AnimNode(AnimNode::ClipType, id),
|
||||||
|
@ -102,13 +103,7 @@ const std::vector<AnimPose>& AnimClip::evaluate(float dt) {
|
||||||
const std::vector<AnimPose>& nextFrame = _anim[nextIndex];
|
const std::vector<AnimPose>& nextFrame = _anim[nextIndex];
|
||||||
float alpha = glm::fract(_frame);
|
float alpha = glm::fract(_frame);
|
||||||
|
|
||||||
for (size_t i = 0; i < _poses.size(); i++) {
|
blend(_poses.size(), &prevFrame[0], &nextFrame[0], alpha, &_poses[0]);
|
||||||
const AnimPose& prevPose = prevFrame[i];
|
|
||||||
const AnimPose& nextPose = nextFrame[i];
|
|
||||||
_poses[i].scale = lerp(prevPose.scale, nextPose.scale, alpha);
|
|
||||||
_poses[i].rot = glm::normalize(glm::lerp(prevPose.rot, nextPose.rot, alpha));
|
|
||||||
_poses[i].trans = lerp(prevPose.trans, nextPose.trans, alpha);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return _poses;
|
return _poses;
|
||||||
|
|
|
@ -37,6 +37,7 @@ public:
|
||||||
enum Type {
|
enum Type {
|
||||||
ClipType = 0,
|
ClipType = 0,
|
||||||
BlendLinearType,
|
BlendLinearType,
|
||||||
|
OverlayType,
|
||||||
NumTypes
|
NumTypes
|
||||||
};
|
};
|
||||||
typedef std::shared_ptr<AnimNode> Pointer;
|
typedef std::shared_ptr<AnimNode> Pointer;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "AnimClip.h"
|
#include "AnimClip.h"
|
||||||
#include "AnimBlendLinear.h"
|
#include "AnimBlendLinear.h"
|
||||||
#include "AnimationLogging.h"
|
#include "AnimationLogging.h"
|
||||||
|
#include "AnimOverlay.h"
|
||||||
#include "AnimNodeLoader.h"
|
#include "AnimNodeLoader.h"
|
||||||
|
|
||||||
struct TypeInfo {
|
struct TypeInfo {
|
||||||
|
@ -27,17 +28,20 @@ struct TypeInfo {
|
||||||
// item to the AnimNode::Type enum. This is by design.
|
// item to the AnimNode::Type enum. This is by design.
|
||||||
static TypeInfo typeInfoArray[AnimNode::NumTypes] = {
|
static TypeInfo typeInfoArray[AnimNode::NumTypes] = {
|
||||||
{ AnimNode::ClipType, "clip" },
|
{ AnimNode::ClipType, "clip" },
|
||||||
{ AnimNode::BlendLinearType, "blendLinear" }
|
{ AnimNode::BlendLinearType, "blendLinear" },
|
||||||
|
{ AnimNode::OverlayType, "overlay" }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef AnimNode::Pointer (*NodeLoaderFunc)(const QJsonObject& jsonObj, const QString& id, const QString& jsonUrl);
|
typedef AnimNode::Pointer (*NodeLoaderFunc)(const QJsonObject& jsonObj, const QString& id, const QString& jsonUrl);
|
||||||
|
|
||||||
static AnimNode::Pointer loadClipNode(const QJsonObject& jsonObj, const QString& id, const QString& jsonUrl);
|
static AnimNode::Pointer loadClipNode(const QJsonObject& jsonObj, const QString& id, const QString& jsonUrl);
|
||||||
static AnimNode::Pointer loadBlendLinearNode(const QJsonObject& jsonObj, const QString& id, const QString& jsonUrl);
|
static AnimNode::Pointer loadBlendLinearNode(const QJsonObject& jsonObj, const QString& id, const QString& jsonUrl);
|
||||||
|
static AnimNode::Pointer loadOverlayNode(const QJsonObject& jsonObj, const QString& id, const QString& jsonUrl);
|
||||||
|
|
||||||
static NodeLoaderFunc nodeLoaderFuncs[AnimNode::NumTypes] = {
|
static NodeLoaderFunc nodeLoaderFuncs[AnimNode::NumTypes] = {
|
||||||
loadClipNode,
|
loadClipNode,
|
||||||
loadBlendLinearNode
|
loadBlendLinearNode,
|
||||||
|
loadOverlayNode
|
||||||
};
|
};
|
||||||
|
|
||||||
#define READ_STRING(NAME, JSON_OBJ, ID, URL) \
|
#define READ_STRING(NAME, JSON_OBJ, ID, URL) \
|
||||||
|
@ -143,6 +147,41 @@ static AnimNode::Pointer loadBlendLinearNode(const QJsonObject& jsonObj, const Q
|
||||||
return std::make_shared<AnimBlendLinear>(id.toStdString(), alpha);
|
return std::make_shared<AnimBlendLinear>(id.toStdString(), alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char* boneSetStrings[AnimOverlay::NumBoneSets] = {
|
||||||
|
"fullBody",
|
||||||
|
"upperBody",
|
||||||
|
"lowerBody",
|
||||||
|
"rightArm",
|
||||||
|
"leftArm",
|
||||||
|
"aboveTheHead",
|
||||||
|
"belowTheHead",
|
||||||
|
"headOnly",
|
||||||
|
"spineOnly",
|
||||||
|
"empty"
|
||||||
|
};
|
||||||
|
|
||||||
|
static AnimOverlay::BoneSet stringToBoneSetEnum(const QString& str) {
|
||||||
|
for (int i = 0; i < (int)AnimOverlay::NumBoneSets; i++) {
|
||||||
|
if (str == boneSetStrings[i]) {
|
||||||
|
return (AnimOverlay::BoneSet)i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AnimOverlay::NumBoneSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AnimNode::Pointer loadOverlayNode(const QJsonObject& jsonObj, const QString& id, const QString& jsonUrl) {
|
||||||
|
|
||||||
|
READ_STRING(boneSet, jsonObj, id, jsonUrl);
|
||||||
|
|
||||||
|
auto boneSetEnum = stringToBoneSetEnum(boneSet);
|
||||||
|
if (boneSetEnum == AnimOverlay::NumBoneSets) {
|
||||||
|
qCCritical(animation) << "AnimNodeLoader, unknown bone set =" << boneSet << ", defaulting to \"fullBody\", url =" << jsonUrl;
|
||||||
|
boneSetEnum = AnimOverlay::FullBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_shared<AnimBlendLinear>(id.toStdString(), boneSetEnum);
|
||||||
|
}
|
||||||
|
|
||||||
AnimNodeLoader::AnimNodeLoader() {
|
AnimNodeLoader::AnimNodeLoader() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
36
libraries/animation/src/AnimOverlay.cpp
Normal file
36
libraries/animation/src/AnimOverlay.cpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
//
|
||||||
|
// AnimOverlay.cpp
|
||||||
|
//
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AnimOverlay.h"
|
||||||
|
#include "AnimUtil.h"
|
||||||
|
|
||||||
|
AnimOverlay::AnimOverlay(const std::string& id, BoneSet boneSet) :
|
||||||
|
AnimNode(AnimNode::OverlayType, id),
|
||||||
|
_boneSet(boneSet) {
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimOverlay::~AnimOverlay() {
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<AnimPose>& AnimOverlay::evaluate(float dt) {
|
||||||
|
if (_children.size() >= 2) {
|
||||||
|
auto underPoses = _children[1]->evaluate(dt);
|
||||||
|
auto overPoses = _children[0]->overlay(dt, underPoses);
|
||||||
|
|
||||||
|
if (underPoses.size() > 0 && underPoses.size() == overPoses.size()) {
|
||||||
|
_poses.resize(underPoses.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < _poses.size(); i++) {
|
||||||
|
float alpha = 1.0f; // TODO: PULL from boneSet
|
||||||
|
blend(1, &underPoses[i], &overPoses[i], alpha, &_poses[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _poses;
|
||||||
|
}
|
58
libraries/animation/src/AnimOverlay.h
Normal file
58
libraries/animation/src/AnimOverlay.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
//
|
||||||
|
// AnimOverlay.h
|
||||||
|
//
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AnimNode.h"
|
||||||
|
|
||||||
|
#ifndef hifi_AnimOverlay_h
|
||||||
|
#define hifi_AnimOverlay_h
|
||||||
|
|
||||||
|
#include "AnimNode.h"
|
||||||
|
|
||||||
|
// Overlay the AnimPoses from one AnimNode on top of another AnimNode.
|
||||||
|
// child[0] is overlayed on top of child[1]. The boneset is used
|
||||||
|
// to control blending on a per-bone bases.
|
||||||
|
|
||||||
|
class AnimOverlay : public AnimNode {
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum BoneSet {
|
||||||
|
FullBody = 0,
|
||||||
|
UpperBodyBoneSet,
|
||||||
|
LowerBodyBoneSet,
|
||||||
|
RightArmBoneSet,
|
||||||
|
LeftArmBoneSet,
|
||||||
|
AboveTheHeadBoneSet,
|
||||||
|
BelowTheHeadBoneSet,
|
||||||
|
HeadOnlyBoneSet,
|
||||||
|
SpineOnlyBoneSet,
|
||||||
|
EmptyBoneSet,
|
||||||
|
NumBoneSets,
|
||||||
|
};
|
||||||
|
|
||||||
|
AnimOverlay(const std::string& id, BoneSet boneSet);
|
||||||
|
virtual ~AnimOverlay() override;
|
||||||
|
|
||||||
|
void setBoneSet(BoneSet boneSet) { _boneSet = boneSet; }
|
||||||
|
BoneSet getBoneSet() const { return _boneSet; }
|
||||||
|
|
||||||
|
virtual const std::vector<AnimPose>& evaluate(float dt) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// for AnimDebugDraw rendering
|
||||||
|
virtual const std::vector<AnimPose>& getPosesInternal() const override;
|
||||||
|
|
||||||
|
std::vector<AnimPose> _poses;
|
||||||
|
BoneSet _boneSet;
|
||||||
|
|
||||||
|
// no copies
|
||||||
|
AnimOverlay(const AnimOverlay&) = delete;
|
||||||
|
AnimOverlay& operator=(const AnimOverlay&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_AnimOverlay_h
|
21
libraries/animation/src/AnimUtil.cpp
Normal file
21
libraries/animation/src/AnimUtil.cpp
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
//
|
||||||
|
// AnimUtil.cpp
|
||||||
|
//
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AnimUtil.h"
|
||||||
|
#include "GLMHelpers.h"
|
||||||
|
|
||||||
|
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];
|
||||||
|
const AnimPose& bPose = b[i];
|
||||||
|
result[i].scale = lerp(aPose.scale, bPose.scale, alpha);
|
||||||
|
result[i].rot = glm::normalize(glm::lerp(aPose.rot, bPose.rot, alpha));
|
||||||
|
result[i].trans = lerp(aPose.trans, bPose.trans, alpha);
|
||||||
|
}
|
||||||
|
}
|
23
libraries/animation/src/AnimUtil.h
Normal file
23
libraries/animation/src/AnimUtil.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//
|
||||||
|
// AnimUtil.h
|
||||||
|
//
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// 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_AnimUtil_h
|
||||||
|
#define hifi_AnimUtil_h
|
||||||
|
|
||||||
|
#include "AnimNode.h"
|
||||||
|
|
||||||
|
// TODO: use restrict keyword
|
||||||
|
// TODO: excellent candidate for simd vectorization.
|
||||||
|
|
||||||
|
// this is where the magic happens
|
||||||
|
void blend(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue