mirror of
https://github.com/lubosz/overte.git
synced 2025-04-26 06:55:39 +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 "GLMHelpers.h"
|
||||
#include "AnimationLogging.h"
|
||||
#include "AnimUtil.h"
|
||||
|
||||
AnimBlendLinear::AnimBlendLinear(const std::string& id, float alpha) :
|
||||
AnimNode(AnimNode::BlendLinearType, id),
|
||||
|
@ -40,13 +41,8 @@ const std::vector<AnimPose>& AnimBlendLinear::evaluate(float dt) {
|
|||
|
||||
if (prevPoses.size() > 0 && prevPoses.size() == nextPoses.size()) {
|
||||
_poses.resize(prevPoses.size());
|
||||
for (size_t i = 0; i < _poses.size(); i++) {
|
||||
const AnimPose& prevPose = prevPoses[i];
|
||||
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);
|
||||
}
|
||||
|
||||
blend(_poses.size(), &prevPoses[0], &nextPoses[0], alpha, &_poses[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "GLMHelpers.h"
|
||||
#include "AnimClip.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) :
|
||||
AnimNode(AnimNode::ClipType, id),
|
||||
|
@ -102,13 +103,7 @@ const std::vector<AnimPose>& AnimClip::evaluate(float dt) {
|
|||
const std::vector<AnimPose>& nextFrame = _anim[nextIndex];
|
||||
float alpha = glm::fract(_frame);
|
||||
|
||||
for (size_t i = 0; i < _poses.size(); i++) {
|
||||
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);
|
||||
}
|
||||
blend(_poses.size(), &prevFrame[0], &nextFrame[0], alpha, &_poses[0]);
|
||||
}
|
||||
|
||||
return _poses;
|
||||
|
|
|
@ -37,6 +37,7 @@ public:
|
|||
enum Type {
|
||||
ClipType = 0,
|
||||
BlendLinearType,
|
||||
OverlayType,
|
||||
NumTypes
|
||||
};
|
||||
typedef std::shared_ptr<AnimNode> Pointer;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "AnimClip.h"
|
||||
#include "AnimBlendLinear.h"
|
||||
#include "AnimationLogging.h"
|
||||
#include "AnimOverlay.h"
|
||||
#include "AnimNodeLoader.h"
|
||||
|
||||
struct TypeInfo {
|
||||
|
@ -27,17 +28,20 @@ struct TypeInfo {
|
|||
// item to the AnimNode::Type enum. This is by design.
|
||||
static TypeInfo typeInfoArray[AnimNode::NumTypes] = {
|
||||
{ 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);
|
||||
|
||||
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 loadOverlayNode(const QJsonObject& jsonObj, const QString& id, const QString& jsonUrl);
|
||||
|
||||
static NodeLoaderFunc nodeLoaderFuncs[AnimNode::NumTypes] = {
|
||||
loadClipNode,
|
||||
loadBlendLinearNode
|
||||
loadBlendLinearNode,
|
||||
loadOverlayNode
|
||||
};
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
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() {
|
||||
|
||||
}
|
||||
|
|
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