Added a spatializer into osgUtil to create a balanced quad/oct tree.

This commit is contained in:
Robert Osfield
2003-12-01 10:28:23 +00:00
parent 532d9a38bf
commit 3c9d1e0603
2 changed files with 215 additions and 2 deletions

View File

@@ -44,12 +44,14 @@ class OSGUTIL_EXPORT Optimizer
SHARE_DUPLICATE_STATE = 0x8,
MERGE_GEOMETRY = 0x10,
CHECK_GEOMETRY = 0x20,
SPATIALIZE_GROUPS = 0x40,
ALL_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS |
REMOVE_REDUNDANT_NODES |
COMBINE_ADJACENT_LODS |
SHARE_DUPLICATE_STATE |
MERGE_GEOMETRY |
CHECK_GEOMETRY
CHECK_GEOMETRY |
SPATIALIZE_GROUPS
};
/** traverse the node and its subgraph with a series of optimization
@@ -213,6 +215,24 @@ class OSGUTIL_EXPORT Optimizer
static bool mergePrimitive(osg::DrawElementsUInt& lhs,osg::DrawElementsUInt& rhs);
};
/** Spatialize scene into a balanced quad/oct tree.*/
class OSGUTIL_EXPORT SpatializeGroupsVisitor : public osg::NodeVisitor
{
public:
SpatializeGroupsVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
virtual void apply(osg::Group& group);
bool divide(unsigned int maxNumTreesPerCell=8);
bool divide(osg::Group* group, unsigned int maxNumTreesPerCell);
typedef std::set<osg::Group*> GroupsToDivideList;
GroupsToDivideList _groupsToDivideList;
};
};
}

View File

@@ -110,7 +110,13 @@ void Optimizer::optimize(osg::Node* node, unsigned int options)
node->accept(mgv);
}
if (options & SPATIALIZE_GROUPS)
{
SpatializeGroupsVisitor sv;
node->accept(sv);
sv.divide();
}
}
@@ -1525,3 +1531,190 @@ bool Optimizer::MergeGeometryVisitor::mergePrimitive(osg::DrawElementsUInt& lhs,
lhs.insert(lhs.end(),rhs.begin(),rhs.end());
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Spatialize the scene to accelerate culling
//
void Optimizer::SpatializeGroupsVisitor::apply(osg::Group& group)
{
if (typeid(group)==typeid(osg::Group) || group.asTransform())
{
_groupsToDivideList.insert(&group);
}
traverse(group);
}
bool Optimizer::SpatializeGroupsVisitor::divide(unsigned int maxNumTreesPerCell)
{
bool divided = false;
for(GroupsToDivideList::iterator itr=_groupsToDivideList.begin();
itr!=_groupsToDivideList.end();
++itr)
{
if (divide(*itr,maxNumTreesPerCell)) divided = true;
}
return divided;
}
bool Optimizer::SpatializeGroupsVisitor::divide(osg::Group* group, unsigned int maxNumTreesPerCell)
{
if (group->getNumChildren()<=maxNumTreesPerCell) return false;
// create the original box.
osg::BoundingBox bb;
unsigned int i;
for(i=0;i<group->getNumChildren();++i)
{
bb.expandBy(group->getChild(i)->getBound().center());
}
float radius = bb.radius();
float divide_distance = radius*0.7f;
bool xAxis = (bb.xMax()-bb.xMin())>divide_distance;
bool yAxis = (bb.yMax()-bb.yMin())>divide_distance;
bool zAxis = (bb.zMax()-bb.zMin())>divide_distance;
std::cout<<"Dividing "<<group->className()<<" num children = "<<group->getNumChildren()<<" xAxis="<<xAxis<<" yAxis="<<yAxis<<" zAxis="<<zAxis<<std::endl;
unsigned int numChildrenOnEntry = group->getNumChildren();
typedef std::pair< osg::BoundingBox, osg::ref_ptr<osg::Group> > BoxGroupPair;
typedef std::vector< BoxGroupPair > Boxes;
Boxes boxes;
boxes.push_back( BoxGroupPair(bb,new osg::Group) );
// divide up on each axis
if (xAxis)
{
unsigned int numCellsToDivide=boxes.size();
for(unsigned int i=0;i<numCellsToDivide;++i)
{
osg::BoundingBox& orig_cell = boxes[i].first;
osg::BoundingBox new_cell = orig_cell;
float xCenter = (orig_cell.xMin()+orig_cell.xMax())*0.5f;
orig_cell.xMax() = xCenter;
new_cell.xMin() = xCenter;
boxes.push_back(BoxGroupPair(new_cell,new osg::Group));
}
}
if (yAxis)
{
unsigned int numCellsToDivide=boxes.size();
for(unsigned int i=0;i<numCellsToDivide;++i)
{
osg::BoundingBox& orig_cell = boxes[i].first;
osg::BoundingBox new_cell = orig_cell;
float yCenter = (orig_cell.yMin()+orig_cell.yMax())*0.5f;
orig_cell.yMax() = yCenter;
new_cell.yMin() = yCenter;
boxes.push_back(BoxGroupPair(new_cell,new osg::Group));
}
}
if (zAxis)
{
unsigned int numCellsToDivide=boxes.size();
for(unsigned int i=0;i<numCellsToDivide;++i)
{
osg::BoundingBox& orig_cell = boxes[i].first;
osg::BoundingBox new_cell = orig_cell;
float zCenter = (orig_cell.zMin()+orig_cell.zMax())*0.5f;
orig_cell.zMax() = zCenter;
new_cell.zMin() = zCenter;
boxes.push_back(BoxGroupPair(new_cell,new osg::Group));
}
}
// create the groups to drop the children into
// bin each child into associated bb group
typedef std::vector< osg::ref_ptr<osg::Node> > NodeList;
NodeList unassignedList;
for(i=0;i<group->getNumChildren();++i)
{
bool assigned = false;
osg::Vec3 center = group->getChild(i)->getBound().center();
for(Boxes::iterator itr=boxes.begin();
itr!=boxes.end() && !assigned;
++itr)
{
if (itr->first.contains(center))
{
// move child from main group into bb group.
(itr->second)->addChild(group->getChild(i));
assigned = true;
}
}
if (!assigned)
{
unassignedList.push_back(group->getChild(i));
}
}
// now transfer nodes across, by :
// first removing from the original group,
// add in the bb groups
// add then the unassigned children.
// first removing from the original group,
group->removeChild(0,group->getNumChildren());
// add in the bb groups
typedef std::vector< osg::ref_ptr<osg::Group> > GroupList;
GroupList groupsToDivideList;
for(Boxes::iterator itr=boxes.begin();
itr!=boxes.end();
++itr)
{
// move child from main group into bb group.
osg::Group* bb_group = (itr->second).get();
if (bb_group->getNumChildren()>0)
{
if (bb_group->getNumChildren()==1)
{
group->addChild(bb_group->getChild(0));
}
else
{
group->addChild(bb_group);
if (bb_group->getNumChildren()>maxNumTreesPerCell)
{
groupsToDivideList.push_back(bb_group);
}
}
}
}
// add then the unassigned children.
for(NodeList::iterator nitr=unassignedList.begin();
nitr!=unassignedList.end();
++nitr)
{
group->addChild(nitr->get());
}
// now call divide on all groups that require it.
for(GroupList::iterator gitr=groupsToDivideList.begin();
gitr!=groupsToDivideList.end();
++gitr)
{
divide(gitr->get(),maxNumTreesPerCell);
}
return (numChildrenOnEntry<group->getNumChildren());
}