Fixed FlattenStaticTransformVisitor bug which related to incorrect handling

of objects which were transformed by multiple matrices at one time - this
cannot be handled in the flattening process (since we only have one piece
of geometry to transform).  This visitor now handles this case by disabling
flattening of any objects and transforms associated in this way.
This commit is contained in:
Robert Osfield 2002-01-22 19:30:51 +00:00
parent d115e143b5
commit f16776da22
2 changed files with 264 additions and 69 deletions

View File

@ -48,13 +48,7 @@ class OSGUTIL_EXPORT Optimizer
{
public:
typedef std::vector<osg::Matrix> MatrixStack;
typedef std::set<osg::Transform*> TransformList;
MatrixStack _matrixStack;
TransformList _transformList;
bool _ignoreDynamicTransforms;
FlattenStaticTransformsVisitor(bool ignoreDynamicTransforms=true):
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
@ -67,6 +61,74 @@ class OSGUTIL_EXPORT Optimizer
void removeTransforms();
protected:
typedef std::vector<osg::Transform*> TransformStack;
typedef std::vector<osg::Matrix> MatrixStack;
struct TransformStruct
{
typedef std::set<osg::Object*> ObjectSet;
TransformStruct():_canBeApplied(true) {}
void add(osg::Object* obj) { _objectSet.insert(obj); }
bool _canBeApplied;
ObjectSet _objectSet;
};
struct ObjectStruct
{
typedef std::set<osg::Transform*> TransformSet;
ObjectStruct():_canBeApplied(true),_matrixSet(false),_moreThanOneMatrixRequired(false) {}
void add(TransformStack& transforms,osg::Matrix& matrix)
{
_transformSet.insert(transforms.begin(),transforms.end());
if (!_matrixSet)
{
_matrixSet = true;
_moreThanOneMatrixRequired = false;
_matrix = matrix;
}
else if (_matrix!=matrix)
{
_moreThanOneMatrixRequired = true;
}
}
bool _canBeApplied;
bool _matrixSet;
bool _moreThanOneMatrixRequired;
osg::Matrix _matrix;
TransformSet _transformSet;
};
typedef std::map<osg::Transform*,TransformStruct> TransformMap;
typedef std::map<osg::Object*,ObjectStruct> ObjectMap;
void disableObject(osg::Object* object)
{
disableObject(_objectMap.find(object));
}
void disableObject(ObjectMap::iterator itr);
void disableTransform(osg::Transform* transform);
void doTransform(osg::Object* obj,osg::Matrix& matrix);
bool _ignoreDynamicTransforms;
MatrixStack _matrixStack;
TransformStack _transformStack;
TransformMap _transformMap;
ObjectMap _objectMap;
};
/** Remove rendundent nodes, such as groups with one single child.*/

View File

@ -24,14 +24,14 @@ void Optimizer::optimize(osg::Node* node, unsigned int options)
node->accept(clv);
clv.combineLODs();
}
/*
if (options & FLATTEN_STATIC_TRANSFORMS)
{
FlattenStaticTransformsVisitor fstv;
node->accept(fstv);
fstv.removeTransforms();
}
*/
if (options & REMOVE_REDUNDENT_NODES)
{
RemoveRedundentNodesVisitor rrnv;
@ -291,13 +291,11 @@ void Optimizer::FlattenStaticTransformsVisitor::apply(osg::Geode& geode)
{
if (!_matrixStack.empty())
{
TransformFunctor tf(_matrixStack.back());
for(int i=0;i<geode.getNumDrawables();++i)
{
geode.getDrawable(i)->applyAttributeOperation(tf);
geode.getDrawable(i)->dirtyBound();
// register each drawable with the objectMap.
_objectMap[geode.getDrawable(i)].add(_transformStack,_matrixStack.back());
}
geode.dirtyBound();
}
}
@ -305,23 +303,8 @@ void Optimizer::FlattenStaticTransformsVisitor::apply(osg::Billboard& billboard)
{
if (!_matrixStack.empty())
{
osg::Matrix& matrix = _matrixStack.back();
osg::Matrix matrix_no_trans = matrix;
matrix_no_trans.setTrans(0.0f,0.0f,0.0f);
TransformFunctor tf(matrix_no_trans);
osg::Vec3 axis = osg::Matrix::transform3x3(tf._im,billboard.getAxis());
axis.normalize();
billboard.setAxis(axis);
for(int i=0;i<billboard.getNumDrawables();++i)
{
billboard.setPos(i,billboard.getPos(i)*matrix);
billboard.getDrawable(i)->applyAttributeOperation(tf);
}
billboard.dirtyBound();
// register ourselves with the objectMap.
_objectMap[&billboard].add(_transformStack,_matrixStack.back());
}
}
@ -329,25 +312,10 @@ void Optimizer::FlattenStaticTransformsVisitor::apply(osg::LOD& lod)
{
if (!_matrixStack.empty())
{
osg::Matrix& matrix = _matrixStack.back();
osg::Matrix matrix_no_trans = matrix;
matrix_no_trans.setTrans(0.0f,0.0f,0.0f);
osg::Vec3 v111(1.0f,1.0f,1.0f);
osg::Vec3 new_v111 = v111*matrix_no_trans;
float ratio = new_v111.length()/v111.length();
// move center point.
lod.setCenter(lod.getCenter()*matrix);
// adjust ranges to new scale.
for(int i=0;i<lod.getNumRanges();++i)
{
lod.setRange(i,lod.getRange(i)*ratio);
// register ourselves with the objectMap.
_objectMap[&lod].add(_transformStack,_matrixStack.back());
}
lod.dirtyBound();
}
traverse(lod);
}
@ -369,25 +337,188 @@ void Optimizer::FlattenStaticTransformsVisitor::apply(osg::Transform& transform)
_matrixStack.push_back(transform.getMatrix()*_matrixStack.back());
}
_transformList.insert(&transform);
_transformStack.push_back(&transform);
// simple traverse the children as if this Transform didn't exist.
traverse(transform);
// reset the matrix to identity.
transform.setMatrix(osg::Matrix::identity());
_transformStack.pop_back();
_matrixStack.pop_back();
}
}
void Optimizer::FlattenStaticTransformsVisitor::doTransform(osg::Object* obj,osg::Matrix& matrix)
{
osg::Drawable* drawable = dynamic_cast<osg::Drawable*>(obj);
if (drawable)
{
TransformFunctor tf(matrix);
drawable->applyAttributeOperation(tf);
drawable->dirtyBound();
return;
}
osg::LOD* lod = dynamic_cast<osg::LOD*>(obj);
if (lod)
{
osg::Matrix matrix_no_trans = matrix;
matrix_no_trans.setTrans(0.0f,0.0f,0.0f);
osg::Vec3 v111(1.0f,1.0f,1.0f);
osg::Vec3 new_v111 = v111*matrix_no_trans;
float ratio = new_v111.length()/v111.length();
// move center point.
lod->setCenter(lod->getCenter()*matrix);
// adjust ranges to new scale.
for(int i=0;i<lod->getNumRanges();++i)
{
lod->setRange(i,lod->getRange(i)*ratio);
}
lod->dirtyBound();
return;
}
osg::Billboard* billboard = dynamic_cast<osg::Billboard*>(obj);
if (billboard)
{
osg::Matrix matrix_no_trans = matrix;
matrix_no_trans.setTrans(0.0f,0.0f,0.0f);
TransformFunctor tf(matrix_no_trans);
osg::Vec3 axis = osg::Matrix::transform3x3(tf._im,billboard->getAxis());
axis.normalize();
billboard->setAxis(axis);
for(int i=0;i<billboard->getNumDrawables();++i)
{
billboard->setPos(i,billboard->getPos(i)*matrix);
billboard->getDrawable(i)->applyAttributeOperation(tf);
}
billboard->dirtyBound();
return;
}
}
void Optimizer::FlattenStaticTransformsVisitor::disableObject(ObjectMap::iterator itr)
{
if (itr==_transformMap.end())
{
// Euston we have a problem..
osg::notify(osg::WARN)<<"Warning: internal error Optimizer::FlattenStaticTransformsVisitor::disableObject()"<<std::endl;
return;
}
if (itr->second._canBeApplied)
{
// we havn't been disabled yet so we need to disable,
itr->second._canBeApplied = false;
// and then inform everybody we have been disabled.
for(ObjectStruct::TransformSet::iterator titr = itr->second._transformSet.begin();
titr != itr->second._transformSet.end();
++titr)
{
disableTransform(*titr);
}
}
}
void Optimizer::FlattenStaticTransformsVisitor::disableTransform(osg::Transform* transform)
{
TransformMap::iterator itr=_transformMap.find(transform);
if (itr==_transformMap.end())
{
// Euston we have a problem..
osg::notify(osg::WARN)<<"Warning: internal error Optimizer::FlattenStaticTransformsVisitor::disableTransform()"<<std::endl;
return;
}
if (itr->second._canBeApplied)
{
// we havn't been disabled yet so we need to disable,
itr->second._canBeApplied = false;
// and then inform everybody we have been disabled.
for(TransformStruct::ObjectSet::iterator oitr = itr->second._objectSet.begin();
oitr != itr->second._objectSet.end();
++oitr)
{
disableObject(*oitr);
}
}
}
void Optimizer::FlattenStaticTransformsVisitor::removeTransforms()
{
for(TransformList::iterator itr=_transformList.begin();
itr!=_transformList.end();
++itr)
// create the TransformMap from the ObjectMap
ObjectMap::iterator oitr;
for(oitr=_objectMap.begin();
oitr!=_objectMap.end();
++oitr)
{
osg::ref_ptr<osg::Transform> transform = *itr;
osg::Object* object = oitr->first;
ObjectStruct& os = oitr->second;
for(ObjectStruct::TransformSet::iterator titr = os._transformSet.begin();
titr != os._transformSet.end();
++titr)
{
_transformMap[*titr].add(object);
}
}
// disable all the objects which have more than one matrix associated
// with them, and then disable all transforms which have an object associated
// them that can't be applied, and then disable all objects which have
// disabled transforms associated, recursing until all disabled
// associativity.
for(oitr=_objectMap.begin();
oitr!=_objectMap.end();
++oitr)
{
ObjectStruct& os = oitr->second;
if (os._canBeApplied)
{
if (os._moreThanOneMatrixRequired)
{
disableObject(oitr);
}
}
}
// transform the objects that can be applied.
for(oitr=_objectMap.begin();
oitr!=_objectMap.end();
++oitr)
{
osg::Object* object = oitr->first;
ObjectStruct& os = oitr->second;
if (os._canBeApplied)
{
doTransform(object,os._matrix);
}
}
// clean up the transforms.
for(TransformMap::iterator titr=_transformMap.begin();
titr!=_transformMap.end();
++titr)
{
if (titr->second._canBeApplied)
{
osg::ref_ptr<osg::Transform> transform = titr->first;
osg::ref_ptr<osg::Group> group = new osg::Group;
int i;
@ -403,9 +534,12 @@ void Optimizer::FlattenStaticTransformsVisitor::removeTransforms()
{
transform->getParent(i)->replaceChild(transform.get(),group.get());
}
}
_transformList.clear();
}
_objectMap.clear();
_transformMap.clear();
_transformStack.clear();
_matrixStack.clear();
}
@ -425,7 +559,6 @@ void Optimizer::RemoveRedundentNodesVisitor::apply(osg::Group& group)
traverse(group);
}
void Optimizer::RemoveRedundentNodesVisitor::removeRedundentNodes()
{
for(NodeList::iterator itr=_redundentNodeList.begin();