3
0
Fork 0
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:
Anthony J. Thibault 2015-08-05 17:05:53 -07:00
parent 2d0315978e
commit 1f8c8adbd6
8 changed files with 185 additions and 16 deletions

View file

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

View file

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

View file

@ -37,6 +37,7 @@ public:
enum Type {
ClipType = 0,
BlendLinearType,
OverlayType,
NumTypes
};
typedef std::shared_ptr<AnimNode> Pointer;

View file

@ -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() {
}

View 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;
}

View 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

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

View 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