From f16776da22f25fda26619e2baaa55496ef4fb996 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 22 Jan 2002 19:30:51 +0000 Subject: [PATCH] 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. --- include/osgUtil/Optimizer | 74 ++++++++++- src/osgUtil/Optimizer.cpp | 259 ++++++++++++++++++++++++++++---------- 2 files changed, 264 insertions(+), 69 deletions(-) diff --git a/include/osgUtil/Optimizer b/include/osgUtil/Optimizer index bb191bfb9..22ddbabc5 100644 --- a/include/osgUtil/Optimizer +++ b/include/osgUtil/Optimizer @@ -48,13 +48,7 @@ class OSGUTIL_EXPORT Optimizer { public: - typedef std::vector MatrixStack; - typedef std::set 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 TransformStack; + typedef std::vector MatrixStack; + + struct TransformStruct + { + typedef std::set ObjectSet; + + TransformStruct():_canBeApplied(true) {} + + void add(osg::Object* obj) { _objectSet.insert(obj); } + + bool _canBeApplied; + ObjectSet _objectSet; + }; + + struct ObjectStruct + { + typedef std::set 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 TransformMap; + typedef std::map 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.*/ diff --git a/src/osgUtil/Optimizer.cpp b/src/osgUtil/Optimizer.cpp index 78970b7d8..877cd6590 100644 --- a/src/osgUtil/Optimizer.cpp +++ b/src/osgUtil/Optimizer.cpp @@ -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;iapplyAttributeOperation(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;iapplyAttributeOperation(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(obj); + if (drawable) + { + TransformFunctor tf(matrix); + drawable->applyAttributeOperation(tf); + drawable->dirtyBound(); + return; + } + + osg::LOD* lod = dynamic_cast(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;igetNumRanges();++i) + { + lod->setRange(i,lod->getRange(i)*ratio); + } + + lod->dirtyBound(); + return; + } + + osg::Billboard* billboard = dynamic_cast(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;igetNumDrawables();++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()"<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()"<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) - { - osg::ref_ptr transform = *itr; - osg::ref_ptr group = new osg::Group; - int i; - for(i=0;igetNumChildren();++i) + // create the TransformMap from the ObjectMap + ObjectMap::iterator oitr; + for(oitr=_objectMap.begin(); + oitr!=_objectMap.end(); + ++oitr) + { + osg::Object* object = oitr->first; + ObjectStruct& os = oitr->second; + + for(ObjectStruct::TransformSet::iterator titr = os._transformSet.begin(); + titr != os._transformSet.end(); + ++titr) { - for(int j=0;jgetNumParents();++j) + _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) { - group->addChild(transform->getChild(i)); + disableObject(oitr); } } - - for(i=transform->getNumParents()-1;i>=0;--i) - { - transform->getParent(i)->replaceChild(transform.get(),group.get()); - } - } - _transformList.clear(); + + // 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 transform = titr->first; + osg::ref_ptr group = new osg::Group; + + int i; + for(i=0;igetNumChildren();++i) + { + for(int j=0;jgetNumParents();++j) + { + group->addChild(transform->getChild(i)); + } + } + + for(i=transform->getNumParents()-1;i>=0;--i) + { + transform->getParent(i)->replaceChild(transform.get(),group.get()); + } + } + } + _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();