Added a spatializer into osgUtil to create a balanced quad/oct tree.
This commit is contained in:
@@ -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;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user