mirror of https://github.com/OpenMW/openmw.git
OSG-Collada animation support
parent
f78a5d795c
commit
6e77ad1f6a
@ -0,0 +1,40 @@
|
||||
#include <components/resource/animation.hpp>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osgAnimation/Channel>
|
||||
|
||||
namespace Resource
|
||||
{
|
||||
Animation::Animation(const Animation& anim, const osg::CopyOp& copyop): osg::Object(anim, copyop),
|
||||
mDuration(0.0f),
|
||||
mStartTime(0.0f)
|
||||
{
|
||||
const osgAnimation::ChannelList& channels = anim.getChannels();
|
||||
for (const osg::ref_ptr<osgAnimation::Channel> channel: channels)
|
||||
addChannel(channel.get()->clone());
|
||||
}
|
||||
|
||||
void Animation::addChannel(osg::ref_ptr<osgAnimation::Channel> pChannel)
|
||||
{
|
||||
mChannels.push_back(pChannel);
|
||||
}
|
||||
|
||||
std::vector<osg::ref_ptr<osgAnimation::Channel>>& Animation::getChannels()
|
||||
{
|
||||
return mChannels;
|
||||
}
|
||||
|
||||
const std::vector<osg::ref_ptr<osgAnimation::Channel>>& Animation::getChannels() const
|
||||
{
|
||||
return mChannels;
|
||||
}
|
||||
|
||||
bool Animation::update (double time)
|
||||
{
|
||||
for (const osg::ref_ptr<osgAnimation::Channel> channel: mChannels)
|
||||
{
|
||||
channel->update(time, 1.0f, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
#ifndef OPENMW_COMPONENTS_RESOURCE_ANIMATION_HPP
|
||||
#define OPENMW_COMPONENTS_RESOURCE_ANIMATION_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <osg/Node>
|
||||
#include <osg/Object>
|
||||
#include <osgAnimation/Channel>
|
||||
|
||||
namespace Resource
|
||||
{
|
||||
/// Stripped down class of osgAnimation::Animation, only needed for OSG's plugin formats like dae
|
||||
class Animation : public osg::Object
|
||||
{
|
||||
public:
|
||||
META_Object(Resource, Animation)
|
||||
|
||||
Animation() :
|
||||
mDuration(0.0), mStartTime(0) {}
|
||||
|
||||
Animation(const Animation&, const osg::CopyOp&);
|
||||
~Animation() {}
|
||||
|
||||
void addChannel (osg::ref_ptr<osgAnimation::Channel> pChannel);
|
||||
|
||||
std::vector<osg::ref_ptr<osgAnimation::Channel>>& getChannels();
|
||||
|
||||
const std::vector<osg::ref_ptr<osgAnimation::Channel>>& getChannels() const;
|
||||
|
||||
bool update (double time);
|
||||
|
||||
protected:
|
||||
double mDuration;
|
||||
double mStartTime;
|
||||
std::vector<osg::ref_ptr<osgAnimation::Channel>> mChannels;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,195 @@
|
||||
#include <components/sceneutil/osgacontroller.hpp>
|
||||
|
||||
#include <osg/Geode>
|
||||
#include <osg/Node>
|
||||
#include <osg/NodeVisitor>
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/StateSet>
|
||||
|
||||
#include <osgAnimation/Animation>
|
||||
#include <osgAnimation/AnimationUpdateCallback>
|
||||
#include <osgAnimation/Channel>
|
||||
#include <osgAnimation/BasicAnimationManager>
|
||||
#include <osgAnimation/Bone>
|
||||
#include <osgAnimation/Sampler>
|
||||
#include <osgAnimation/Skeleton>
|
||||
#include <osgAnimation/RigGeometry>
|
||||
#include <osgAnimation/UpdateMatrixTransform>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/resource/animation.hpp>
|
||||
#include <components/sceneutil/controller.hpp>
|
||||
#include <components/sceneutil/keyframe.hpp>
|
||||
|
||||
namespace OsgaController
|
||||
{
|
||||
LinkVisitor::LinkVisitor() : osg::NodeVisitor( TRAVERSE_ALL_CHILDREN )
|
||||
{
|
||||
mAnimation = nullptr;
|
||||
}
|
||||
|
||||
void LinkVisitor::link(osgAnimation::UpdateMatrixTransform* umt)
|
||||
{
|
||||
const osgAnimation::ChannelList& channels = mAnimation->getChannels();
|
||||
for (const osg::ref_ptr<osgAnimation::Channel> channel: channels)
|
||||
{
|
||||
const std::string& channelName = channel->getName();
|
||||
const std::string& channelTargetName = channel->getTargetName();
|
||||
|
||||
if (channelTargetName != umt->getName()) continue;
|
||||
|
||||
// check if we can link a StackedTransformElement to the current Channel
|
||||
for (auto stackedTransform : umt->getStackedTransforms())
|
||||
{
|
||||
osgAnimation::StackedTransformElement* element = stackedTransform.get();
|
||||
if (element && !element->getName().empty() && channelName == element->getName())
|
||||
{
|
||||
osgAnimation::Target* target = element->getOrCreateTarget();
|
||||
if (target)
|
||||
{
|
||||
channel->setTarget(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinkVisitor::handle_stateset(osg::StateSet* stateset)
|
||||
{
|
||||
if (!stateset)
|
||||
return;
|
||||
const osg::StateSet::AttributeList& attributeList = stateset->getAttributeList();
|
||||
for (auto attribute : attributeList)
|
||||
{
|
||||
osg::StateAttribute* sattr = attribute.second.first.get();
|
||||
osgAnimation::UpdateMatrixTransform* umt = dynamic_cast<osgAnimation::UpdateMatrixTransform*>(sattr->getUpdateCallback()); //Can this even be in sa?
|
||||
if (umt) link(umt);
|
||||
}
|
||||
}
|
||||
|
||||
void LinkVisitor::setAnimation(Resource::Animation* animation)
|
||||
{
|
||||
mAnimation = animation;
|
||||
}
|
||||
|
||||
void LinkVisitor::apply(osg::Node& node)
|
||||
{
|
||||
osg::StateSet* st = node.getStateSet();
|
||||
if (st)
|
||||
handle_stateset(st);
|
||||
|
||||
osg::Callback* cb = node.getUpdateCallback();
|
||||
while (cb)
|
||||
{
|
||||
osgAnimation::UpdateMatrixTransform* umt = dynamic_cast<osgAnimation::UpdateMatrixTransform*>(cb);
|
||||
if (umt)
|
||||
if (node.getName() != "root") link(umt);
|
||||
cb = cb->getNestedCallback();
|
||||
}
|
||||
|
||||
traverse( node );
|
||||
}
|
||||
|
||||
void LinkVisitor::apply(osg::Geode& node)
|
||||
{
|
||||
for (unsigned int i = 0; i < node.getNumDrawables(); i++)
|
||||
{
|
||||
osg::Drawable* drawable = node.getDrawable(i);
|
||||
if (drawable && drawable->getStateSet())
|
||||
handle_stateset(drawable->getStateSet());
|
||||
}
|
||||
apply(static_cast<osg::Node&>(node));
|
||||
}
|
||||
|
||||
KeyframeController::KeyframeController(const KeyframeController ©, const osg::CopyOp ©op) : SceneUtil::KeyframeController(copy, copyop)
|
||||
{
|
||||
mLinker = nullptr;
|
||||
}
|
||||
|
||||
osg::Vec3f KeyframeController::getTranslation(float time) const
|
||||
{
|
||||
osg::Vec3f translationValue;
|
||||
std::string animationName;
|
||||
float newTime = time;
|
||||
|
||||
//Find the correct animation based on time
|
||||
for (auto emulatedAnimation : mEmulatedAnimations)
|
||||
{
|
||||
if (time > emulatedAnimation.mStartTime && time < emulatedAnimation.mStopTime)
|
||||
{
|
||||
newTime = time - emulatedAnimation.mStartTime;
|
||||
animationName = emulatedAnimation.mName;
|
||||
}
|
||||
}
|
||||
|
||||
//Find the root transform track in animation
|
||||
for (auto mergedAnimationTrack : mMergedAnimationTracks)
|
||||
{
|
||||
if (mergedAnimationTrack->getName() != animationName) continue;
|
||||
|
||||
const osgAnimation::ChannelList& channels = mergedAnimationTrack->getChannels();
|
||||
|
||||
for (const osg::ref_ptr<osgAnimation::Channel> channel: channels)
|
||||
{
|
||||
if (channel->getTargetName() != "root" || channel->getName() != "transform") continue;
|
||||
|
||||
if ( osgAnimation::MatrixLinearSampler* templateSampler = dynamic_cast<osgAnimation::MatrixLinearSampler*> (channel->getSampler()) )
|
||||
{
|
||||
osg::Matrixf matrix;
|
||||
templateSampler->getValueAt(newTime, matrix);
|
||||
translationValue = matrix.getTrans();
|
||||
return osg::Vec3f(translationValue[0], translationValue[1], translationValue[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return osg::Vec3f();
|
||||
}
|
||||
|
||||
void KeyframeController::update(float time, std::string animationName)
|
||||
{
|
||||
for (auto mergedAnimationTrack : mMergedAnimationTracks)
|
||||
{
|
||||
if (mergedAnimationTrack->getName() == animationName) mergedAnimationTrack->update(time);
|
||||
}
|
||||
}
|
||||
|
||||
void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv)
|
||||
{
|
||||
if (hasInput())
|
||||
{
|
||||
if (mNeedToLink)
|
||||
{
|
||||
for (auto mergedAnimationTrack : mMergedAnimationTracks)
|
||||
{
|
||||
if (!mLinker.valid()) mLinker = new LinkVisitor();
|
||||
mLinker->setAnimation(mergedAnimationTrack);
|
||||
node->accept(*mLinker);
|
||||
}
|
||||
mNeedToLink = false;
|
||||
}
|
||||
|
||||
float time = getInputValue(nv);
|
||||
|
||||
for (auto emulatedAnimation : mEmulatedAnimations)
|
||||
{
|
||||
if (time > emulatedAnimation.mStartTime && time < emulatedAnimation.mStopTime)
|
||||
{
|
||||
update(time - emulatedAnimation.mStartTime, emulatedAnimation.mName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traverse(node, nv);
|
||||
}
|
||||
|
||||
void KeyframeController::setEmulatedAnimations(std::vector<SceneUtil::EmulatedAnimation> emulatedAnimations)
|
||||
{
|
||||
mEmulatedAnimations = emulatedAnimations;
|
||||
}
|
||||
|
||||
void KeyframeController::addMergedAnimationTrack(osg::ref_ptr<Resource::Animation> animationTrack)
|
||||
{
|
||||
mMergedAnimationTracks.emplace_back(animationTrack);
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
#ifndef OPENMW_COMPONENTS_SCENEUTIL_OSGACONTROLLER_HPP
|
||||
#define OPENMW_COMPONENTS_SCENEUTIL_OSGACONTROLLER_HPP
|
||||
|
||||
#include <osg/Node>
|
||||
#include <osg/NodeVisitor>
|
||||
#include <osg/StateSet>
|
||||
#include <osg/ref_ptr>
|
||||
#include <osgAnimation/Animation>
|
||||
#include <osgAnimation/AnimationUpdateCallback>
|
||||
#include <osgAnimation/Channel>
|
||||
#include <osgAnimation/BasicAnimationManager>
|
||||
#include <osgAnimation/StackedTransform>
|
||||
#include <osgAnimation/UpdateMatrixTransform>
|
||||
|
||||
#include <components/sceneutil/controller.hpp>
|
||||
#include <components/sceneutil/keyframe.hpp>
|
||||
#include <components/resource/animation.hpp>
|
||||
|
||||
namespace OsgaController
|
||||
{
|
||||
class LinkVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
LinkVisitor();
|
||||
|
||||
virtual void link(osgAnimation::UpdateMatrixTransform* umt);
|
||||
|
||||
virtual void handle_stateset(osg::StateSet* stateset);
|
||||
|
||||
virtual void setAnimation(Resource::Animation* animation);
|
||||
|
||||
virtual void apply(osg::Node& node);
|
||||
|
||||
virtual void apply(osg::Geode& node);
|
||||
|
||||
protected:
|
||||
Resource::Animation* mAnimation;
|
||||
};
|
||||
|
||||
class KeyframeController : public SceneUtil::KeyframeController
|
||||
{
|
||||
public:
|
||||
/// @brief Handles the animation for osgAnimation formats
|
||||
KeyframeController() {};
|
||||
|
||||
KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop);
|
||||
|
||||
META_Object(OsgaController, KeyframeController)
|
||||
|
||||
/// @brief Handles the location of the instance
|
||||
osg::Vec3f getTranslation(float time) const override;
|
||||
|
||||
/// @brief Calls animation track update()
|
||||
void update(float time, std::string animationName);
|
||||
|
||||
/// @brief Called every frame for osgAnimation
|
||||
void operator() (osg::Node*, osg::NodeVisitor*) override;
|
||||
|
||||
/// @brief Sets details of the animations
|
||||
void setEmulatedAnimations(std::vector<SceneUtil::EmulatedAnimation> emulatedAnimations);
|
||||
|
||||
/// @brief Adds an animation track to a model
|
||||
void addMergedAnimationTrack(osg::ref_ptr<Resource::Animation> animationTrack);
|
||||
private:
|
||||
bool mNeedToLink = true;
|
||||
osg::ref_ptr<LinkVisitor> mLinker;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue