Futher improvements and fixes to osg::AnimationPath, and the osglight
demo to show it action.
This commit is contained in:
@@ -7,7 +7,6 @@
|
||||
|
||||
#include <osg/Matrix>
|
||||
#include <osg/Quat>
|
||||
#include <osg/Transform>
|
||||
|
||||
#include <map>
|
||||
|
||||
@@ -17,29 +16,27 @@ namespace osg {
|
||||
* Subclassed from Transform::ComputeTransformCallback allows AnimationPath to
|
||||
* be attached directly to Transform nodes to move subgraphs around the scene.
|
||||
*/
|
||||
class SG_EXPORT AnimationPath : public Transform::ComputeTransformCallback
|
||||
class SG_EXPORT AnimationPath : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
AnimationPath() {}
|
||||
AnimationPath():_loopMode(LOOP) {}
|
||||
|
||||
/** get the local transformation matrix for a point in time.*/
|
||||
virtual bool getMatrix(double time,Matrix& matrix) const;
|
||||
|
||||
/** get the local inverse transformation matrix for a point in time.*/
|
||||
virtual bool getInverse(double time,Matrix& matrix) const;
|
||||
|
||||
/** Get the transformation matrix which moves from local coords to world coords.*/
|
||||
virtual const bool computeLocalToWorldMatrix(Matrix& matrix,const Transform* transform, NodeVisitor* nv) const;
|
||||
|
||||
/** Get the transformation matrix which moves from world coords to local coords.*/
|
||||
virtual const bool computeWorldToLocalMatrix(Matrix& matrix,const Transform* transform, NodeVisitor* nv) const;
|
||||
|
||||
struct Key
|
||||
struct ControlPoint
|
||||
{
|
||||
Key() {}
|
||||
ControlPoint() {}
|
||||
|
||||
Key(const osg::Vec3& position, const osg::Quat& rotation, const osg::Vec3& scale):
|
||||
ControlPoint(const osg::Vec3& position):
|
||||
_position(position),
|
||||
_rotation(),
|
||||
_scale() {}
|
||||
|
||||
ControlPoint(const osg::Vec3& position, const osg::Quat& rotation):
|
||||
_position(position),
|
||||
_rotation(rotation),
|
||||
_scale() {}
|
||||
|
||||
ControlPoint(const osg::Vec3& position, const osg::Quat& rotation, const osg::Vec3& scale):
|
||||
_position(position),
|
||||
_rotation(rotation),
|
||||
_scale(scale) {}
|
||||
@@ -48,7 +45,7 @@ class SG_EXPORT AnimationPath : public Transform::ComputeTransformCallback
|
||||
osg::Quat _rotation;
|
||||
osg::Vec3 _scale;
|
||||
|
||||
inline void interpolate(const float ratio,const Key& first, const Key& second)
|
||||
inline void interpolate(const float ratio,const ControlPoint& first, const ControlPoint& second)
|
||||
{
|
||||
float one_minus_ratio = 1.0f-ratio;
|
||||
_position = first._position*one_minus_ratio + second._position*ratio;
|
||||
@@ -71,16 +68,53 @@ class SG_EXPORT AnimationPath : public Transform::ComputeTransformCallback
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** get the transformation matrix for a point in time.*/
|
||||
bool getMatrix(double time,Matrix& matrix) const
|
||||
{
|
||||
ControlPoint cp;
|
||||
if (!getInterpolatedControlPoint(time,cp)) return false;
|
||||
cp.getMatrix(matrix);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** get the inverse transformation matrix for a point in time.*/
|
||||
bool getInverse(double time,Matrix& matrix) const
|
||||
{
|
||||
ControlPoint cp;
|
||||
if (!getInterpolatedControlPoint(time,cp)) return false;
|
||||
cp.getInverse(matrix);
|
||||
return true;
|
||||
}
|
||||
|
||||
void insert(double time,const Key& key);
|
||||
/** get the local ControlPoint frame for a point in time.*/
|
||||
virtual bool getInterpolatedControlPoint(double time,ControlPoint& ControlPoint) const;
|
||||
|
||||
void insert(double time,const ControlPoint& ControlPoint);
|
||||
|
||||
double getFirstTime() const { if (!_timeControlPointMap.empty()) return _timeControlPointMap.begin()->first; else return 0.0;}
|
||||
double getLastTime() const { if (!_timeControlPointMap.empty()) return _timeControlPointMap.rbegin()->first; else return 0.0;}
|
||||
double getPeriod() const { return getLastTime()-getFirstTime();}
|
||||
|
||||
enum LoopMode
|
||||
{
|
||||
SWING,
|
||||
LOOP,
|
||||
NO_LOOPING
|
||||
};
|
||||
|
||||
void setLoopMode(LoopMode lm) { _loopMode = lm; }
|
||||
|
||||
LoopMode getLoopMode() const { return _loopMode; }
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~AnimationPath() {}
|
||||
|
||||
typedef std::map<double,Key> TimeKeyMap;
|
||||
typedef std::map<double,ControlPoint> TimeControlPointMap;
|
||||
|
||||
TimeKeyMap _timeKeyMap;
|
||||
TimeControlPointMap _timeControlPointMap;
|
||||
LoopMode _loopMode;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -84,30 +84,11 @@ class SG_EXPORT Billboard : public Geode
|
||||
virtual const bool removeDrawable( Drawable *gset );
|
||||
|
||||
|
||||
/** Callback attached to an Billboard which allows the users to customize the billboard orientation calculation during cull traversal.*/
|
||||
struct ComputeBillboardCallback : public osg::Referenced
|
||||
{
|
||||
/** Get the transformation matrix which moves from local coords to world coords.*/
|
||||
virtual const bool computeMatrix(Matrix& modelview, const Billboard* billboard, const Vec3& eye_local, const Vec3& pos_local) const = 0;
|
||||
};
|
||||
|
||||
/** Set the ComputeBillboardCallback which allows users to attach custom computation of the local transformation as
|
||||
* seen by cull traversers and alike.*/
|
||||
void setComputeBillboardCallback(ComputeBillboardCallback* ctc) { _computeBillboardCallback=ctc; }
|
||||
|
||||
/** Get the non const ComputeBillboardCallback.*/
|
||||
ComputeBillboardCallback* getComputeBillboardCallback() { return _computeBillboardCallback.get(); }
|
||||
|
||||
/** Get the const ComputeBillboardCallback.*/
|
||||
const ComputeBillboardCallback* getComputeBillboardCallback() const { return _computeBillboardCallback.get(); }
|
||||
|
||||
|
||||
inline const bool getMatrix(Matrix& modelview, const Vec3& eye_local, const Vec3& pos_local) const
|
||||
{
|
||||
if (_computeBillboardCallback.valid())
|
||||
return _computeBillboardCallback->computeMatrix(modelview,this,eye_local,pos_local);
|
||||
else
|
||||
return computeMatrix(modelview,eye_local,pos_local);
|
||||
return computeMatrix(modelview,eye_local,pos_local);
|
||||
}
|
||||
|
||||
virtual const bool computeMatrix(Matrix& modelview, const Vec3& eye_local, const Vec3& pos_local) const;
|
||||
@@ -131,7 +112,6 @@ class SG_EXPORT Billboard : public Geode
|
||||
Vec3 _axis;
|
||||
Vec3 _normal;
|
||||
PositionList _positionList;
|
||||
ref_ptr<ComputeBillboardCallback> _computeBillboardCallback;
|
||||
|
||||
// used internally as cache of which what _axis is aligned to help
|
||||
// deicde which method of rotation to use.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#define OSG_MATRIXTRANSFORM 1
|
||||
|
||||
#include <osg/Transform>
|
||||
#include <osg/AnimationPath>
|
||||
|
||||
namespace osg {
|
||||
|
||||
@@ -78,6 +79,23 @@ class SG_EXPORT MatrixTransform : public Transform
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Callback which can be attached to a MatrixTransform as an app
|
||||
* callback to allow it to follow the path defined by a AnimationPath.*/
|
||||
class AnimationPathCallback : public NodeCallback
|
||||
{
|
||||
public:
|
||||
|
||||
AnimationPathCallback(AnimationPath* ap):
|
||||
_animationPath(ap),
|
||||
_firstTime(0.0) {}
|
||||
|
||||
/** implements the callback*/
|
||||
virtual void operator()(Node* node, NodeVisitor* nv);
|
||||
|
||||
ref_ptr<AnimationPath> _animationPath;
|
||||
double _firstTime;
|
||||
};
|
||||
|
||||
protected :
|
||||
|
||||
virtual ~MatrixTransform();
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
|
||||
#include <osg/Group>
|
||||
#include <osg/Transform>
|
||||
#include <osg/AnimationPath>
|
||||
#include <osg/Quat>
|
||||
|
||||
namespace osg {
|
||||
|
||||
/** PositionAttitideTransform - is Transfrom the set the coordinates transform
|
||||
/** PositionAttitideTransform - is Transform the set the coordinates transform
|
||||
up via a Vec3 position and Quat attitude.
|
||||
*/
|
||||
class SG_EXPORT PositionAttitudeTransform : public Transform
|
||||
@@ -48,6 +49,26 @@ class SG_EXPORT PositionAttitudeTransform : public Transform
|
||||
|
||||
virtual const bool computeWorldToLocalMatrix(Matrix& matrix,NodeVisitor* nv) const;
|
||||
|
||||
|
||||
/** Callback which can be attached to a PositionAttitudeTransform
|
||||
* as an app callback to allow it to follow the path defined by a
|
||||
* AnimationPath.*/
|
||||
class AnimationPathCallback : public NodeCallback
|
||||
{
|
||||
public:
|
||||
|
||||
AnimationPathCallback(AnimationPath* ap):
|
||||
_animationPath(ap),
|
||||
_firstTime(0.0) {}
|
||||
|
||||
/** implements the callback*/
|
||||
virtual void operator()(Node* node, NodeVisitor* nv);
|
||||
|
||||
ref_ptr<AnimationPath> _animationPath;
|
||||
double _firstTime;
|
||||
};
|
||||
|
||||
|
||||
protected :
|
||||
|
||||
|
||||
|
||||
@@ -113,19 +113,6 @@ struct TransformCallback : public osg::Transform::ComputeTransformCallback
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct BillboardCallback : public osg::Billboard::ComputeBillboardCallback
|
||||
{
|
||||
/** Get the transformation matrix which moves from local coords to world coords.*/
|
||||
virtual const bool computeMatrix(osg::Matrix& modelview, const osg::Billboard* billboard, const osg::Vec3& eye_local, const osg::Vec3& pos_local) const
|
||||
{
|
||||
std::cout<<"ComputeBillboardCallback - pre billboard->computeMatrix"<<std::endl;
|
||||
bool result = billboard->computeMatrix(modelview,eye_local,pos_local);
|
||||
std::cout<<"ComputeBillboardCallback - post billboard->computeMatrix"<<std::endl;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct DrawableAppCallback : public osg::Drawable::AppCallback
|
||||
{
|
||||
virtual void app(osg::NodeVisitor*, osg::Drawable* drawable)
|
||||
@@ -178,12 +165,6 @@ class InsertCallbacksVisitor : public osg::NodeVisitor
|
||||
}
|
||||
}
|
||||
|
||||
virtual void apply(osg::Billboard& node)
|
||||
{
|
||||
node.setComputeBillboardCallback(new BillboardCallback());
|
||||
apply((osg::Geode&)node);
|
||||
}
|
||||
|
||||
virtual void apply(osg::Transform& node)
|
||||
{
|
||||
node.setComputeTransformCallback(new TransformCallback());
|
||||
|
||||
@@ -109,22 +109,22 @@ osg::Node* createLights(osg::BoundingBox& bb,osg::StateSet* rootStateSet)
|
||||
|
||||
lightS2->setStateSetModes(*rootStateSet,osg::StateAttribute::ON);
|
||||
|
||||
osg::PositionAttitudeTransform* pat = new osg::PositionAttitudeTransform();
|
||||
osg::MatrixTransform* mt = new osg::MatrixTransform();
|
||||
{
|
||||
// set up the animation path
|
||||
osg::AnimationPath* animationPath = new osg::AnimationPath;
|
||||
animationPath->insert(0.0,osg::AnimationPath::Key(bb.corner(0)));
|
||||
animationPath->insert(1.0,osg::AnimationPath::Key(bb.corner(1)));
|
||||
animationPath->insert(2.0,osg::AnimationPath::Key(bb.corner(2)));
|
||||
animationPath->insert(3.0,osg::AnimationPath::Key(bb.corner(3)));
|
||||
animationPath->insert(4.0,osg::AnimationPath::Key(bb.corner(4)));
|
||||
animationPath->insert(5.0,osg::AnimationPath::Key(bb.corner(5)));
|
||||
animationPath->insert(6.0,osg::AnimationPath::Key(bb.corner(6)));
|
||||
animationPath->insert(7.0,osg::AnimationPath::Key(bb.corner(7)));
|
||||
animationPath->insert(8.0,osg::AnimationPath::Key(bb.corner(0)));
|
||||
animationPath->insert(0.0,osg::AnimationPath::ControlPoint(bb.corner(0)));
|
||||
animationPath->insert(1.0,osg::AnimationPath::ControlPoint(bb.corner(1)));
|
||||
animationPath->insert(2.0,osg::AnimationPath::ControlPoint(bb.corner(2)));
|
||||
animationPath->insert(3.0,osg::AnimationPath::ControlPoint(bb.corner(3)));
|
||||
animationPath->insert(4.0,osg::AnimationPath::ControlPoint(bb.corner(4)));
|
||||
animationPath->insert(5.0,osg::AnimationPath::ControlPoint(bb.corner(5)));
|
||||
animationPath->insert(6.0,osg::AnimationPath::ControlPoint(bb.corner(6)));
|
||||
animationPath->insert(7.0,osg::AnimationPath::ControlPoint(bb.corner(7)));
|
||||
animationPath->insert(8.0,osg::AnimationPath::ControlPoint(bb.corner(0)));
|
||||
animationPath->setLoopMode(osg::AnimationPath::SWING);
|
||||
|
||||
// attach it to the transform as an app callback.
|
||||
pat->setAppCallback(new osg::PositionAttitudeTransform::AnimationPathCallback(animationPath));
|
||||
mt->setAppCallback(new osg::MatrixTransform::AnimationPathCallback(animationPath));
|
||||
}
|
||||
|
||||
// create marker for point light.
|
||||
@@ -144,12 +144,12 @@ osg::Node* createLights(osg::BoundingBox& bb,osg::StateSet* rootStateSet)
|
||||
osg::Geode* markerGeode = new osg::Geode;
|
||||
markerGeode->addDrawable(marker);
|
||||
|
||||
pat->addChild(lightS2);
|
||||
pat->addChild(markerGeode);
|
||||
mt->addChild(lightS2);
|
||||
mt->addChild(markerGeode);
|
||||
|
||||
lightGroup->addChild(lightS2);
|
||||
|
||||
lightGroup->addChild(pat);
|
||||
lightGroup->addChild(mt);
|
||||
|
||||
return lightGroup;
|
||||
}
|
||||
|
||||
@@ -3,23 +3,50 @@
|
||||
|
||||
using namespace osg;
|
||||
|
||||
void AnimationPath::insert(double time,const Key& key)
|
||||
void AnimationPath::insert(double time,const ControlPoint& ControlPoint)
|
||||
{
|
||||
_timeKeyMap[time] = key;
|
||||
_timeControlPointMap[time] = ControlPoint;
|
||||
}
|
||||
|
||||
bool AnimationPath::getMatrix(double time,Matrix& matrix) const
|
||||
bool AnimationPath::getInterpolatedControlPoint(double time,ControlPoint& controlPoint) const
|
||||
{
|
||||
if (_timeKeyMap.empty()) return false;
|
||||
|
||||
TimeKeyMap::const_iterator second = _timeKeyMap.lower_bound(time);
|
||||
if (second==_timeKeyMap.begin())
|
||||
if (_timeControlPointMap.empty()) return false;
|
||||
|
||||
|
||||
|
||||
switch(_loopMode)
|
||||
{
|
||||
second->second.getMatrix(matrix);
|
||||
case(SWING):
|
||||
{
|
||||
double modulated_time = (time - getFirstTime())/(getPeriod()*2.0);
|
||||
double fraction_part = modulated_time - floor(modulated_time);
|
||||
if (fraction_part>0.5) fraction_part = 1.0-fraction_part;
|
||||
|
||||
time = (fraction_part*2.0) * getPeriod();
|
||||
break;
|
||||
}
|
||||
case(LOOP):
|
||||
{
|
||||
double modulated_time = (time - getFirstTime())/getPeriod();
|
||||
double fraction_part = modulated_time - floor(modulated_time);
|
||||
time = fraction_part * getPeriod();
|
||||
break;
|
||||
}
|
||||
case(NO_LOOPING):
|
||||
// no need to modulate the time.
|
||||
break;
|
||||
}
|
||||
else if (second!=_timeKeyMap.end())
|
||||
|
||||
|
||||
|
||||
TimeControlPointMap::const_iterator second = _timeControlPointMap.lower_bound(time);
|
||||
if (second==_timeControlPointMap.begin())
|
||||
{
|
||||
TimeKeyMap::const_iterator first = second;
|
||||
controlPoint = second->second;
|
||||
}
|
||||
else if (second!=_timeControlPointMap.end())
|
||||
{
|
||||
TimeControlPointMap::const_iterator first = second;
|
||||
--first;
|
||||
|
||||
// we have both a lower bound and the next item.
|
||||
@@ -28,92 +55,17 @@ bool AnimationPath::getMatrix(double time,Matrix& matrix) const
|
||||
double delta_time = second->first - first->first;
|
||||
|
||||
if (delta_time==0.0)
|
||||
first->second.getMatrix(matrix);
|
||||
controlPoint = first->second;
|
||||
else
|
||||
{
|
||||
Key key;
|
||||
key.interpolate((time - first->first)/delta_time,
|
||||
first->second,
|
||||
second->second);
|
||||
key.getMatrix(matrix);
|
||||
}
|
||||
}
|
||||
else // (second==_timeKeyMap.end())
|
||||
{
|
||||
_timeKeyMap.rbegin().base()->second.getMatrix(matrix);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AnimationPath::getInverse(double time,Matrix& matrix) const
|
||||
{
|
||||
if (_timeKeyMap.empty()) return false;
|
||||
|
||||
TimeKeyMap::const_iterator second = _timeKeyMap.lower_bound(time);
|
||||
if (second==_timeKeyMap.begin())
|
||||
{
|
||||
second->second.getInverse(matrix);
|
||||
}
|
||||
else if (second!=_timeKeyMap.end())
|
||||
{
|
||||
TimeKeyMap::const_iterator first = second;
|
||||
--first;
|
||||
|
||||
// we have both a lower bound and the next item.
|
||||
|
||||
// deta_time = second.time - first.time
|
||||
double delta_time = second->first - first->first;
|
||||
|
||||
if (delta_time==0.0)
|
||||
first->second.getInverse(matrix);
|
||||
else
|
||||
{
|
||||
Key key;
|
||||
key.interpolate((time - first->first)/delta_time,
|
||||
first->second,
|
||||
second->second);
|
||||
key.getInverse(matrix);
|
||||
}
|
||||
}
|
||||
else // (second==_timeKeyMap.end())
|
||||
{
|
||||
_timeKeyMap.rbegin().base()->second.getInverse(matrix);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool AnimationPath::getKeyFrame(double time,Key& key) const
|
||||
{
|
||||
if (_timeKeyMap.empty()) return false;
|
||||
|
||||
TimeKeyMap::const_iterator second = _timeKeyMap.lower_bound(time);
|
||||
if (second==_timeKeyMap.begin())
|
||||
{
|
||||
key = second->second;
|
||||
}
|
||||
else if (second!=_timeKeyMap.end())
|
||||
{
|
||||
TimeKeyMap::const_iterator first = second;
|
||||
--first;
|
||||
|
||||
// we have both a lower bound and the next item.
|
||||
|
||||
// deta_time = second.time - first.time
|
||||
double delta_time = second->first - first->first;
|
||||
|
||||
if (delta_time==0.0)
|
||||
key = first->second;
|
||||
else
|
||||
{
|
||||
key.interpolate((time - first->first)/delta_time,
|
||||
controlPoint.interpolate((time - first->first)/delta_time,
|
||||
first->second,
|
||||
second->second);
|
||||
}
|
||||
}
|
||||
else // (second==_timeKeyMap.end())
|
||||
else // (second==_timeControlPointMap.end())
|
||||
{
|
||||
key = _timeKeyMap.rbegin().base()->second;
|
||||
controlPoint = _timeControlPointMap.rbegin()->second;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ Billboard::Billboard(const Billboard& billboard,const CopyOp& copyop):
|
||||
_axis(billboard._axis),
|
||||
_normal(billboard._normal),
|
||||
_positionList(billboard._positionList),
|
||||
_computeBillboardCallback(_computeBillboardCallback),
|
||||
_cachedMode(billboard._cachedMode),
|
||||
_side(billboard._side) {}
|
||||
|
||||
|
||||
@@ -30,3 +30,21 @@ MatrixTransform::MatrixTransform(const Matrix& mat )
|
||||
MatrixTransform::~MatrixTransform()
|
||||
{
|
||||
}
|
||||
|
||||
void MatrixTransform::AnimationPathCallback::operator()(Node* node, NodeVisitor* nv)
|
||||
{
|
||||
MatrixTransform* mt = dynamic_cast<MatrixTransform*>(node);
|
||||
if (mt &&
|
||||
_animationPath.valid() &&
|
||||
nv->getVisitorType()==NodeVisitor::APP_VISITOR &&
|
||||
nv->getFrameStamp())
|
||||
{
|
||||
double time = nv->getFrameStamp()->getReferenceTime();
|
||||
if (_firstTime==0.0) _firstTime = time;
|
||||
Matrix matrix;
|
||||
if (_animationPath->getMatrix(time-_firstTime,matrix))
|
||||
{
|
||||
mt->setMatrix(matrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,11 +51,11 @@ void PositionAttitudeTransform::AnimationPathCallback::operator()(Node* node, No
|
||||
{
|
||||
double time = nv->getFrameStamp()->getReferenceTime();
|
||||
if (_firstTime==0.0) _firstTime = time;
|
||||
AnimationPath::Key key;
|
||||
if (_animationPath->getKeyFrame(time-_firstTime,key))
|
||||
AnimationPath::ControlPoint cp;
|
||||
if (_animationPath->getInterpolatedControlPoint(time-_firstTime,cp))
|
||||
{
|
||||
pat->setPosition(key._position);
|
||||
pat->setAttitude(key._rotation);
|
||||
pat->setPosition(cp._position);
|
||||
pat->setAttitude(cp._rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user