From Kristofer Tingdahl, reimplement of AntiSquish node to avoid the use of an update callback.

From Robert Osfield, small ammendments to clean up header.
This commit is contained in:
Robert Osfield 2014-01-20 11:00:09 +00:00
parent 6246cd5d85
commit 15399bbf35
2 changed files with 110 additions and 100 deletions

View File

@ -17,20 +17,15 @@
#include <osgManipulator/Export> #include <osgManipulator/Export>
#include <osg/Matrix> #include <osg/Transform>
#include <osg/CopyOp> #include <OpenThreads/Mutex>
#include <osg/NodeVisitor>
#include <osg/NodeCallback>
#include <osg/MatrixTransform>
#include <osg/Quat>
#include <osg/Vec3>
namespace osgManipulator { namespace osgManipulator {
/** /**
* Class that performs the Anti Squish by making the scaling uniform along all axes. * Class that performs the Anti Squish by making the scaling uniform along all axes.
*/ */
class OSGMANIPULATOR_EXPORT AntiSquish: public osg::MatrixTransform class OSGMANIPULATOR_EXPORT AntiSquish: public osg::Transform
{ {
public : public :
AntiSquish(); AntiSquish();
@ -48,7 +43,7 @@ class OSGMANIPULATOR_EXPORT AntiSquish: public osg::MatrixTransform
{ {
_pivot = pvt; _pivot = pvt;
_usePivot = true; _usePivot = true;
_dirty = true; _cacheDirty = true;
} }
const osg::Vec3d& getPivot() const { return _pivot; } const osg::Vec3d& getPivot() const { return _pivot; }
@ -57,18 +52,19 @@ class OSGMANIPULATOR_EXPORT AntiSquish: public osg::MatrixTransform
{ {
_position = pos; _position = pos;
_usePosition = true; _usePosition = true;
_dirty = true; _cacheDirty = true;
} }
const osg::Vec3d& getPosition() const { return _position; } const osg::Vec3d& getPosition() const { return _position; }
osg::Matrix computeUnSquishedMatrix(const osg::Matrix&, bool& flag); bool computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor*) const;
bool computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor*) const;
protected: protected:
virtual ~AntiSquish(); virtual ~AntiSquish();
osg::NodeCallback* _asqCallback; bool computeUnSquishedMatrix(const osg::NodeVisitor*,osg::Matrix&) const;
osg::Vec3d _pivot; osg::Vec3d _pivot;
bool _usePivot; bool _usePivot;
@ -76,8 +72,10 @@ class OSGMANIPULATOR_EXPORT AntiSquish: public osg::MatrixTransform
osg::Vec3d _position; osg::Vec3d _position;
bool _usePosition; bool _usePosition;
bool _dirty; mutable OpenThreads::Mutex _cacheLock;
osg::Matrix _cachedLocalToWorld; mutable bool _cacheDirty;
mutable osg::Matrix _cacheLocalToWorld;
mutable osg::Matrix _cache;
}; };
} }

View File

@ -12,71 +12,35 @@
*/ */
//osgManipulator - Copyright (C) 2007 Fugro-Jason B.V. //osgManipulator - Copyright (C) 2007 Fugro-Jason B.V.
#include <osgManipulator/AntiSquish> #include <osgManipulator/AntiSquish>
using namespace osgManipulator; using namespace osgManipulator;
namespace
AntiSquish::AntiSquish() : _usePivot(true), _usePosition(false), _cacheDirty( true )
{ {
class AntiSquishCallback: public osg::NodeCallback
{
public:
AntiSquishCallback(AntiSquish* asq) : osg::NodeCallback(), _antiSquish(asq) {}
virtual ~AntiSquishCallback() {};
virtual void operator() (osg::Node* node, osg::NodeVisitor* nv)
{
// Get the node path.
osg::NodePath np = nv->getNodePath();
// Remove the last node which is the anti squish node itself.
np.pop_back();
// Get the accumulated modeling matrix.
osg::Matrix localToWorld = osg::computeLocalToWorld(np);
// compute the unsquished matrix.
bool flag = false;
osg::Matrix _unsquishedMatrix = _antiSquish->computeUnSquishedMatrix(localToWorld, flag);
if (flag)
_antiSquish->setMatrix(_unsquishedMatrix);
traverse(node,nv);
} }
protected: AntiSquish::AntiSquish(const osg::Vec3d& pivot) : _pivot(pivot), _usePivot(true), _usePosition(false), _cacheDirty( true )
AntiSquish* _antiSquish;
};
}
AntiSquish::AntiSquish() : _usePivot(true), _usePosition(false)
{ {
_asqCallback = new AntiSquishCallback(this);
setUpdateCallback(_asqCallback);
}
AntiSquish::AntiSquish(const osg::Vec3d& pivot) : _pivot(pivot), _usePivot(true), _usePosition(false)
{
_asqCallback = new AntiSquishCallback(this);
setUpdateCallback(_asqCallback);
} }
AntiSquish::AntiSquish(const osg::Vec3d& pivot, const osg::Vec3d& pos) AntiSquish::AntiSquish(const osg::Vec3d& pivot, const osg::Vec3d& pos)
: _pivot(pivot), _usePivot(true), _position(pos), _usePosition(true) : _pivot(pivot), _usePivot(true), _position(pos), _usePosition(true), _cacheDirty( true )
{ {
_asqCallback = new AntiSquishCallback(this);
setUpdateCallback(_asqCallback);
} }
AntiSquish::AntiSquish(const AntiSquish& pat,const osg::CopyOp& copyop) : AntiSquish::AntiSquish(const AntiSquish& pat,const osg::CopyOp& copyop) :
MatrixTransform(pat,copyop), Transform(pat,copyop),
_asqCallback(pat._asqCallback),
_pivot(pat._pivot), _pivot(pat._pivot),
_usePivot(pat._usePivot), _usePivot(pat._usePivot),
_position(pat._position), _position(pat._position),
_usePosition(pat._usePosition), _usePosition(pat._usePosition),
_cachedLocalToWorld(pat._cachedLocalToWorld) _cacheDirty(pat._cacheDirty),
_cacheLocalToWorld(pat._cacheLocalToWorld),
_cache(pat._cache)
{ {
} }
@ -84,32 +48,87 @@ AntiSquish::~AntiSquish()
{ {
} }
osg::Matrix AntiSquish::computeUnSquishedMatrix(const osg::Matrix& LTW, bool& flag)
bool AntiSquish::computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const
{ {
osg::Matrix unsquishedMatrix;
if ( !computeUnSquishedMatrix( nv, unsquishedMatrix ) )
return Transform::computeLocalToWorldMatrix( matrix, nv );
if (_referenceFrame==RELATIVE_RF)
{
matrix.preMult(unsquishedMatrix);
}
else // absolute
{
matrix = unsquishedMatrix;
}
return true;
}
bool AntiSquish::computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const
{
osg::Matrix unsquishedMatrix;
if ( !computeUnSquishedMatrix( nv, unsquishedMatrix ) )
return Transform::computeWorldToLocalMatrix( matrix, nv );
osg::Matrixd inverse;
inverse.invert( unsquishedMatrix );
if (_referenceFrame==RELATIVE_RF)
{
matrix.postMult(inverse);
}
else // absolute
{
matrix = inverse;
}
return true;
}
bool AntiSquish::computeUnSquishedMatrix(const osg::NodeVisitor* nv, osg::Matrix& unsquished) const
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _cacheLock );
if ( !nv )
{
if ( !_cacheDirty )
{
unsquished = _cache;
return true;
}
return false;
}
osg::NodePath np = nv->getNodePath();
// Remove the last node which is the anti squish node itself.
np.pop_back();
// Get the accumulated modeling matrix.
const osg::Matrix localToWorld = osg::computeLocalToWorld(np);
if ( !_cacheDirty && _cacheLocalToWorld==localToWorld )
{
unsquished = _cache;
return true;
}
osg::Vec3d t, s; osg::Vec3d t, s;
osg::Quat r, so; osg::Quat r, so;
if (LTW == _cachedLocalToWorld && _dirty == false) localToWorld.decompose(t, r, s, so);
{
flag = false;
return osg::Matrix::identity();
}
_cachedLocalToWorld = LTW;
LTW.decompose(t, r, s, so);
// Let's take an average of the scale. // Let's take an average of the scale.
double av = (s[0] + s[1] + s[2])/3.0; double av = (s[0] + s[1] + s[2])/3.0;
s[0] = av; s[1] = av; s[2]=av; s[0] = av; s[1] = av; s[2]=av;
if (av == 0) if (av == 0)
{ return false;
flag = false;
return osg::Matrix::identity();
}
osg::Matrix unsquished;
// //
// Final Matrix: [-Pivot][SO]^[S][SO][R][T][Pivot][LOCALTOWORLD]^[position] // Final Matrix: [-Pivot][SO]^[S][SO][R][T][Pivot][LOCALTOWORLD]^[position]
@ -122,10 +141,7 @@ osg::Matrix AntiSquish::computeUnSquishedMatrix(const osg::Matrix& LTW, bool& fl
osg::Matrix tmps, invtmps; osg::Matrix tmps, invtmps;
so.get(tmps); so.get(tmps);
if (!invtmps.invert(tmps)) if (!invtmps.invert(tmps))
{ return false;
flag = false;
return osg::Matrix::identity();
}
//SO^ //SO^
unsquished.postMult(invtmps); unsquished.postMult(invtmps);
@ -139,11 +155,9 @@ osg::Matrix AntiSquish::computeUnSquishedMatrix(const osg::Matrix& LTW, bool& fl
unsquished.postMultTranslate(t); unsquished.postMultTranslate(t);
osg::Matrix invltw; osg::Matrix invltw;
if (!invltw.invert(LTW)) if (!invltw.invert(localToWorld))
{ return false;
flag = false;
return osg::Matrix::identity();
}
// LTW^ // LTW^
unsquished.postMult( invltw ); unsquished.postMult( invltw );
@ -158,33 +172,31 @@ osg::Matrix AntiSquish::computeUnSquishedMatrix(const osg::Matrix& LTW, bool& fl
osg::Matrix tmps, invtmps; osg::Matrix tmps, invtmps;
so.get(tmps); so.get(tmps);
if (!invtmps.invert(tmps)) if (!invtmps.invert(tmps))
{ return false;
flag = false;
return osg::Matrix::identity();
}
unsquished.postMult(invtmps); unsquished.postMult(invtmps);
unsquished.postMultScale(s); unsquished.postMultScale(s);
unsquished.postMult(tmps); unsquished.postMult(tmps);
unsquished.postMultRotate(r); unsquished.postMultRotate(r);
unsquished.postMultTranslate(t); unsquished.postMultTranslate(t);
osg::Matrix invltw; osg::Matrix invltw;
if (!invltw.invert(LTW)) if (!invltw.invert(localToWorld))
{ return false;
flag = false;
return osg::Matrix::identity();
}
unsquished.postMult( invltw ); unsquished.postMult( invltw );
} }
if (unsquished.isNaN()) if (unsquished.isNaN())
{ return false;
flag = false;
return osg::Matrix::identity();
}
flag = true; _cache = unsquished;
_dirty = false; _cacheLocalToWorld = localToWorld;
return unsquished; _cacheDirty = false;
//As Transform::computeBounde calls us without a node-path it relies on
//The cache. Hence a new _cache affects the bound.
const_cast<AntiSquish*>(this)->dirtyBound();
return true;
} }