Added osgUtil::Optimizer which contains four visitor each designed for doing

different types of optimization on the scene graph - state optimization,
flattening static transforms, combining LOD's and removing redundent groups.
The new Optimizer replaces the once seperate OptimizerStateVisitor.
This commit is contained in:
Robert Osfield
2001-10-19 14:22:02 +00:00
parent 54d490e24b
commit ccc3d3fd8a
7 changed files with 673 additions and 580 deletions

View File

@@ -18,319 +18,7 @@
#include <osgGLUT/glut>
#include <osgGLUT/Viewer>
#include <osgUtil/OptimizeStateVisitor>
class TransformFunctor : public osg::Drawable::AttributeFunctor
{
public:
osg::Matrix _m;
osg::Matrix _im;
TransformFunctor(const osg::Matrix& m):
osg::Drawable::AttributeFunctor(osg::Drawable::COORDS|osg::Drawable::NORMALS)
{
_m = m;
_im.invert(_m);
}
virtual ~TransformFunctor() {}
virtual bool apply(osg::Drawable::AttributeBitMask abm,osg::Vec3* begin,osg::Vec3* end)
{
if (abm == osg::Drawable::COORDS)
{
for (osg::Vec3* itr=begin;itr<end;++itr)
{
(*itr) = (*itr)*_m;
}
return true;
}
else if (abm == osg::Drawable::NORMALS)
{
for (osg::Vec3* itr=begin;itr<end;++itr)
{
// note post mult by inverse for normals.
(*itr) = osg::Matrix::transform3x3(_im,(*itr));
(*itr).normalize();
}
return true;
}
return false;
}
};
class FlattenStaticTransformsVisitor : public osg::NodeVisitor
{
public:
typedef std::vector<osg::Matrix> MatrixStack;
MatrixStack _matrixStack;
typedef std::set<osg::Transform*> TransformList;
TransformList _transformList;
FlattenStaticTransformsVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
virtual void apply(osg::Geode& geode)
{
if (!_matrixStack.empty())
{
TransformFunctor tf(_matrixStack.back());
for(int i=0;i<geode.getNumDrawables();++i)
{
geode.getDrawable(i)->applyAttributeOperation(tf);
}
}
}
virtual void apply(osg::Billboard& billboard)
{
if (!_matrixStack.empty())
{
osg::Matrix& matrix = _matrixStack.back();
TransformFunctor tf(matrix);
osg::Vec3 axis = osg::Matrix::transform3x3(tf._im,billboard.getAxis());
billboard.setAxis(axis);
for(int i=0;i<billboard.getNumDrawables();++i)
{
billboard.setPos(i,billboard.getPos(i)*matrix);
billboard.getDrawable(i)->applyAttributeOperation(tf);
}
}
}
virtual void apply(osg::LOD& lod)
{
if (!_matrixStack.empty())
{
lod.setCenter(lod.getCenter()*_matrixStack.back());
}
traverse(lod);
}
virtual void apply(osg::Transform& transform)
{
if (_matrixStack.empty())
{
_matrixStack.push_back(transform.getMatrix());
}
else
{
_matrixStack.push_back(transform.getMatrix()*_matrixStack.back());
}
traverse(transform);
_transformList.insert(&transform);
// reset the matrix to identity.
transform.getMatrix().makeIdent();
_matrixStack.pop_back();
}
void removeTransforms()
{
for(TransformList::iterator itr=_transformList.begin();
itr!=_transformList.end();
++itr)
{
osg::ref_ptr<osg::Transform> transform = *itr;
osg::ref_ptr<osg::Group> group = new osg::Group;
int i;
for(i=0;i<transform->getNumChildren();++i)
{
for(int j=0;j<transform->getNumParents();++j)
{
group->addChild(transform->getChild(i));
}
}
for(i=transform->getNumParents()-1;i>=0;--i)
{
transform->getParent(i)->replaceChild(transform.get(),group.get());
}
}
_transformList.clear();
}
};
class RemoveRedundentNodesVisitor : public osg::NodeVisitor
{
public:
typedef std::set<osg::Node*> NodeList;
NodeList _redundentNodeList;
RemoveRedundentNodesVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
virtual void apply(osg::Group& group)
{
if (typeid(group)==typeid(osg::Group))
{
if (group.getNumParents()>0 && group.getNumChildren()<=1)
{
_redundentNodeList.insert(&group);
}
}
traverse(group);
}
void removeRedundentNodes()
{
for(NodeList::iterator itr=_redundentNodeList.begin();
itr!=_redundentNodeList.end();
++itr)
{
osg::ref_ptr<osg::Group> group = dynamic_cast<osg::Group*>(*itr);
if (group.valid())
{
for(int j=group->getNumParents()-1;j>=0;--j)
{
for(int i=0;i<group->getNumChildren();++i)
{
group->getParent(j)->addChild(group->getChild(i));
}
group->getParent(j)->removeChild(group.get());
}
}
}
_redundentNodeList.clear();
}
};
class CombineLODsVisitor : public osg::NodeVisitor
{
public:
typedef std::set<osg::Group*> GroupList;
GroupList _groupList;
CombineLODsVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
virtual void apply(osg::LOD& lod)
{
for(int i=0;i<lod.getNumParents();++i)
{
if (typeid(*lod.getParent(i))==typeid(osg::Group))
{
_groupList.insert(lod.getParent(i));
}
}
traverse(lod);
}
void combineLODs()
{
for(GroupList::iterator itr=_groupList.begin();
itr!=_groupList.end();
++itr)
{
osg::Group* group = *itr;
typedef std::set<osg::LOD*> LODSet;
LODSet lodChildren;
for(int i=0;i<group->getNumChildren();++i)
{
osg::Node* child = group->getChild(i);
osg::LOD* lod = dynamic_cast<osg::LOD*>(child);
if (lod)
{
if (lod->getNumRanges()-1==lod->getNumChildren())
{
lodChildren.insert(lod);
}
else
{
// wonky LOD, numRanges should = numChildren+1
}
}
}
if (lodChildren.size()>=2)
{
osg::BoundingBox bb;
LODSet::iterator lod_itr;
for(lod_itr=lodChildren.begin();
lod_itr!=lodChildren.end();
++lod_itr)
{
bb.expandBy((*lod_itr)->getCenter());
}
if (bb.radius()<1e-2)
{
typedef std::pair<float,float> RangePair;
typedef std::multimap<RangePair,osg::Node*> RangeMap;
RangeMap rangeMap;
float maxRange = 0.0f;
for(lod_itr=lodChildren.begin();
lod_itr!=lodChildren.end();
++lod_itr)
{
osg::LOD* lod = *lod_itr;
for(int i=0;i<lod->getNumRanges()-1;++i)
{
if (maxRange<lod->getRange(i+1)) maxRange = lod->getRange(i+1);
rangeMap.insert(RangeMap::value_type(RangePair(lod->getRange(i),lod->getRange(i+1)),lod->getChild(i)));
}
}
// create new LOD containing all other LOD's children.
osg::LOD* newLOD = new osg::LOD;
newLOD->setName("newLOD");
newLOD->setCenter(bb.center());
int i=0;
for(RangeMap::iterator c_itr=rangeMap.begin();
c_itr!=rangeMap.end();
++c_itr,++i)
{
newLOD->setRange(i,c_itr->first.first);
newLOD->addChild(c_itr->second);
}
newLOD->setRange(i,maxRange);
// add LOD into parent.
group->addChild(newLOD);
// remove all the old LOD's from group.
for(lod_itr=lodChildren.begin();
lod_itr!=lodChildren.end();
++lod_itr)
{
group->removeChild(*lod_itr);
}
}
}
}
_groupList.clear();
}
};
#include <osgUtil/Optimizer>
/*
@@ -452,28 +140,10 @@ int main( int argc, char **argv )
osg::Timer_t after_load = timer.tick();
cout << "Time for load = "<<timer.delta_s(before_load,after_load)<<" seconds"<<endl;
// note, the Microsoft visual C++ compilers can't handle the STL
// in the OptimizeStateVisitor and crash if we run it. For the
// time being we'll just not use the optimize visitor under windows.
#ifndef WIN32
// optimize the state in scene graph, removing duplicate state.
osgUtil::OptimizeStateVisitor osv;
rootnode->accept(osv);
osv.optimize();
#endif
CombineLODsVisitor clv;
rootnode->accept(clv);
clv.combineLODs();
FlattenStaticTransformsVisitor fstv;
rootnode->accept(fstv);
fstv.removeTransforms();
RemoveRedundentNodesVisitor rrnv;
rootnode->accept(rrnv);
rrnv.removeRedundentNodes();
// run optimization over the scene graph
osgUtil::Optimizer optimzer;
optimzer.optimize(rootnode);
// initialize the viewer.
osgGLUT::Viewer viewer;