From Michael Platings,

- Animations with equal priority are now weighted correctly relative to each other
- (minor) Channels no longer store their weight as the only time it's used is in update() when Animation can pass in the weight directly
From Cedric Pinson,
- I adjusted the quaternion blending to keep the commutativy property
This commit is contained in:
Cedric Pinson
2009-08-26 09:24:02 +00:00
parent c56dd6faa5
commit 3c45fb1e6c
9 changed files with 92 additions and 83 deletions

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
@@ -71,7 +71,7 @@ namespace osgAnimation
void setWeight (float weight);
float getWeight() const;
bool update (float time);
bool update (float time, int priority = 0);
void resetTargets();
void setPlaymode (PlayMode mode) { _playmode = mode; }

View File

@@ -37,7 +37,7 @@ namespace osgAnimation
virtual ~Channel();
virtual Channel* clone() const = 0;
virtual void update(float time) = 0;
virtual void update(float time, float weight, int priority) = 0;
virtual void reset() = 0;
virtual Target* getTarget() = 0;
virtual bool setTarget(Target*) = 0;
@@ -51,9 +51,6 @@ namespace osgAnimation
const std::string& getTargetName() const;
void setTargetName(const std::string& name);
float getWeight() const;
void setWeight(float w);
virtual Sampler* getSampler() = 0;
virtual const Sampler* getSampler() const = 0;
@@ -61,7 +58,6 @@ namespace osgAnimation
std::string _targetName;
std::string _name;
float _weight;
};
@@ -92,14 +88,14 @@ namespace osgAnimation
}
virtual ~TemplateChannel() {}
virtual void update(float time)
virtual void update(float time, float weight, int priority)
{
// skip if weight == 0
if (_weight < 1e-4)
if (weight < 1e-4)
return;
typename SamplerType::UsingType value;
_sampler->getValueAt(time, value);
_target->update(_weight, value);
_target->update(weight, value, priority);
}
virtual void reset() { _target->reset(); }
virtual Target* getTarget() { return _target.get();}

View File

@@ -36,13 +36,13 @@ namespace osgAnimation
Target();
virtual ~Target();
virtual void normalize() = 0;
float getWeight() const { return _weight; }
void reset() { _weight = 0;}
void reset() { _weight = 0; _priorityWeight = 0; }
int getCount() const { return referenceCount(); }
float getWeight() const { return _weight; }
protected:
void addWeight(float w) { _weight += w; }
float _weight;
float _priorityWeight;
int _lastPriority;
};
@@ -54,72 +54,87 @@ namespace osgAnimation
TemplateTarget() {}
TemplateTarget(const T& v) { setValue(v); }
void update(float weight, const T& val)
inline void lerp(float t, const T& a, const T& b);
/**
* The priority is used to detect a change of priority
* It's important to update animation target in priority
* order. eg:
* all animation with priority 1
* all animation with priority 0
* all animation with priority -1
* ...
*/
void update(float weight, const T& val, int priority)
{
if (!_weight)
_target = val * weight;
if (_weight || _priorityWeight)
{
if (_lastPriority != priority)
{
// change in priority
// add to weight with the same previous priority cumulated weight
_weight += _priorityWeight * (1.0 - _weight);
_priorityWeight = 0;
_lastPriority = priority;
}
_priorityWeight += weight;
float t = (1.0 - _weight) * weight / _priorityWeight;
lerp(t, _target, val);
}
else
{
weight = (1.0 - _weight) * weight;
_target += val * weight;
_priorityWeight = weight;
_lastPriority = priority;
_target = val;
}
addWeight(weight);
}
const T& getValue() const { return _target;}
const T& getValue() const { return _target; }
void normalize()
{
float weightSummed = getWeight();
if (fabs(weightSummed) < 1e-4 || fabs(weightSummed-1) < 1e-4)
return;
(_target) /= weightSummed;
}
inline void normalize();
void setValue(const T& value) { _target = value;}
void setValue(const T& value) { _target = value; }
protected:
T _target;
};
// Target Specialisation for Quaternions
template <>
class TemplateTarget< osg::Quat > : public Target
template <class T>
inline void TemplateTarget<T>::normalize()
{
public:
TemplateTarget () {}
TemplateTarget (const osg::Quat& q) { setValue(q); }
_weight += _priorityWeight * (1.0f - _weight);
if (_weight < 0.9999f )
if (_weight > 0.0001f)
_target /= _weight; // rescale by default
}
const osg::Quat& getValue() const { return _target;}
void update(float weight, const osg::Quat& val)
{
if (!_weight)
_target = val * weight;
else
template <class T>
inline void TemplateTarget<T>::lerp(float t, const T& a, const T& b)
{
_target = a * (1.0f - t) + b * t;
}
template <>
inline void TemplateTarget<osg::Quat>::lerp(float t, const osg::Quat& a, const osg::Quat& b)
{
_target = a * (1.0f - t) + b * t;
osg::Quat::value_type len2 = _target.length2();
if ( len2 != 1.0 && len2 != 0.0)
_target *= 1.0/sqrt(len2);
}
template <>
inline void TemplateTarget<osg::Quat>::normalize()
{
_weight += _priorityWeight * (1.0f - _weight);
if (_weight < 0.9999f )
if (_weight > 0.0001f)
{
weight = (1.0 - _weight) * weight;
_target += val * weight;
osg::Quat::value_type len2 = _target.length2(); // normalize
if ( len2 != 1.0 && len2 != 0.0)
_target *= 1.0/sqrt(len2);
}
addWeight(weight);
}
// maybe normalize could be non virtual and put on ITarget
void normalize()
{
float weightSummed = getWeight();
if (fabs(weightSummed) < 1e-4 || fabs(weightSummed-1.0) < 1e-4)
return;
(_target) /= weightSummed;
}
void setValue(const osg::Quat& value) { _target = value;}
protected:
osg::Quat _target;
};
}
typedef TemplateTarget<osg::Quat> QuatTarget;
typedef TemplateTarget<osg::Vec3> Vec3Target;

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
@@ -95,7 +95,7 @@ void Animation::setWeight (float weight)
_weight = weight;
}
bool Animation::update (float time)
bool Animation::update (float time, int priority)
{
if (!_duration) // if not initialized then do it
computeDuration();
@@ -138,8 +138,7 @@ bool Animation::update (float time)
ChannelList::const_iterator chan;
for( chan=_channels.begin(); chan!=_channels.end(); ++chan)
{
(*chan)->setWeight(_weight);
(*chan)->update(t);
(*chan)->update(t, _weight, priority);
}
return true;
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
@@ -90,10 +90,11 @@ void BasicAnimationManager::update (double time)
{
// update all animation
std::vector<int> toremove;
int priority = iterAnim->first;
AnimationList& list = iterAnim->second;
for (unsigned int i = 0; i < list.size(); i++)
{
if (! list[i]->update(time))
if (! list[i]->update(time, priority))
{
// debug
// std::cout << list[i]->getName() << " finished at " << time << std::endl;

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
@@ -15,12 +15,11 @@
#include <osgAnimation/Channel>
using namespace osgAnimation;
Channel::Channel() { _weight=1; }
Channel::Channel() {}
Channel::~Channel() {}
Channel::Channel(const Channel& channel) : osg::Referenced(channel),
_targetName(channel._targetName),
_name(channel._name),
_weight(channel._weight)
_name(channel._name)
{
}
@@ -29,7 +28,3 @@ void Channel::setName (const std::string& name) { _name = name; }
const std::string& Channel::getTargetName() const { return _targetName;}
void Channel::setTargetName (const std::string& name) { _targetName = name; }
float Channel::getWeight() const { return _weight;}
void Channel::setWeight(float w) { _weight = w;}

View File

@@ -202,7 +202,9 @@ void MorphGeometry::transformSoftwareMethod()
}
}
UpdateMorph::UpdateMorph(const UpdateMorph& apc,const osg::CopyOp& copyop) : AnimationUpdateCallback<osg::NodeCallback>(apc, copyop)
UpdateMorph::UpdateMorph(const UpdateMorph& apc,const osg::CopyOp& copyop) :
osg::Object(apc, copyop),
AnimationUpdateCallback<osg::NodeCallback>(apc, copyop)
{
}
@@ -271,7 +273,7 @@ bool UpdateMorph::link(osgAnimation::Channel* channel)
}
else
{
std::cerr << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl;
osg::notify(osg::WARN) << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl;
}
return false;
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
@@ -18,5 +18,5 @@
using namespace osgAnimation;
Target::Target() { reset();}
Target::Target() : _weight(0), _priorityWeight(0), _lastPriority(0) {}
Target::~Target() {}

View File

@@ -146,6 +146,7 @@ bool Animation_readChannel(osgAnimation::Channel* pChannel, Input& fr)
}
pChannel->setTargetName(target);
// we dont need this info
float weight = 1.0;
if (fr.matchSequence("weight %f"))
{
@@ -153,7 +154,7 @@ bool Animation_readChannel(osgAnimation::Channel* pChannel, Input& fr)
fr += 2;
iteratorAdvanced = true;
}
pChannel->setWeight(weight);
// pChannel->setWeight(weight);
return iteratorAdvanced;
}
@@ -546,7 +547,7 @@ void Animation_writeChannel(const std::string& channelString, ChannelType* pChan
fw.indent() << "name \"" << pChannel->getName() << "\"" << std::endl;
fw.indent() << "target \"" << pChannel->getTargetName() << "\"" << std::endl;
fw.indent() << "weight " << pChannel->getWeight() << std::endl;
// fw.indent() << "weight " << pChannel->getWeight() << std::endl;
ContainerType* kfc = pChannel->getSamplerTyped()->getKeyframeContainerTyped();
if (kfc)