From Terry Welsh, new flatten static transforms visitor that duplicates subgraphs that are shared beneath differnt static transforms
From Robert Osfield, made a range of changes to Terry's visitor integrating it into osgUtil::Optimizer and changing the code to use a style more like the rest of the OSG.
This commit is contained in:
parent
ce13510b47
commit
be185cb3af
@ -83,6 +83,7 @@ class OSGUTIL_EXPORT Optimizer
|
|||||||
FLATTEN_BILLBOARDS = 0x2000,
|
FLATTEN_BILLBOARDS = 0x2000,
|
||||||
TEXTURE_ATLAS_BUILDER = 0x4000,
|
TEXTURE_ATLAS_BUILDER = 0x4000,
|
||||||
STATIC_OBJECT_DETECTION = 0x8000,
|
STATIC_OBJECT_DETECTION = 0x8000,
|
||||||
|
FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS = 0x100,
|
||||||
DEFAULT_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS |
|
DEFAULT_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS |
|
||||||
REMOVE_REDUNDANT_NODES |
|
REMOVE_REDUNDANT_NODES |
|
||||||
REMOVE_LOADED_PROXY_NODES |
|
REMOVE_LOADED_PROXY_NODES |
|
||||||
@ -92,7 +93,7 @@ class OSGUTIL_EXPORT Optimizer
|
|||||||
CHECK_GEOMETRY |
|
CHECK_GEOMETRY |
|
||||||
OPTIMIZE_TEXTURE_SETTINGS |
|
OPTIMIZE_TEXTURE_SETTINGS |
|
||||||
STATIC_OBJECT_DETECTION,
|
STATIC_OBJECT_DETECTION,
|
||||||
ALL_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS |
|
ALL_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS |
|
||||||
REMOVE_REDUNDANT_NODES |
|
REMOVE_REDUNDANT_NODES |
|
||||||
REMOVE_LOADED_PROXY_NODES |
|
REMOVE_LOADED_PROXY_NODES |
|
||||||
COMBINE_ADJACENT_LODS |
|
COMBINE_ADJACENT_LODS |
|
||||||
@ -250,7 +251,10 @@ class OSGUTIL_EXPORT Optimizer
|
|||||||
|
|
||||||
/** Flatten Static Transform nodes by applying their transform to the
|
/** Flatten Static Transform nodes by applying their transform to the
|
||||||
* geometry on the leaves of the scene graph, then removing the
|
* geometry on the leaves of the scene graph, then removing the
|
||||||
* now redundant transforms.*/
|
* now redundant transforms. Static transformed Subgraphs that have multiple
|
||||||
|
* parental paths above them are not flattened, if you require this then
|
||||||
|
* the subgraphs have to be duplicated - for this use the
|
||||||
|
* FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor. */
|
||||||
class OSGUTIL_EXPORT FlattenStaticTransformsVisitor : public BaseOptimizerVisitor
|
class OSGUTIL_EXPORT FlattenStaticTransformsVisitor : public BaseOptimizerVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -282,6 +286,36 @@ class OSGUTIL_EXPORT Optimizer
|
|||||||
TransformSet _transformSet;
|
TransformSet _transformSet;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor is similar to
|
||||||
|
* to FlattenStaticTransformsVisitor in that is desgined to remove static transforms
|
||||||
|
* from the scene graph, pushing down the transforms to the geometry leaves of the scene graph,
|
||||||
|
* but with the difference that any subgraphs that are shared between different transforms
|
||||||
|
* of duplicated and flatten individually. This results in more static transforms
|
||||||
|
* being removed, but also means that more data is generated, and as a result may
|
||||||
|
* not always be the most appropriate flatten visitor to use.*/
|
||||||
|
class FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor : public BaseOptimizerVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor(Optimizer* optimizer=0):
|
||||||
|
BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS) {}
|
||||||
|
|
||||||
|
virtual void reset();
|
||||||
|
|
||||||
|
virtual void apply(osg::Group& group);
|
||||||
|
virtual void apply(osg::Transform& transform);
|
||||||
|
virtual void apply(osg::LOD& lod);
|
||||||
|
virtual void apply(osg::Geode& geode);
|
||||||
|
virtual void apply(osg::Billboard& billboard);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void transformDrawables(osg::Geode& geode);
|
||||||
|
void transformBillboard(osg::Billboard& billboard);
|
||||||
|
|
||||||
|
std::vector<osg::Matrix> _matrixStack;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/** Combine Static Transform nodes that sit above one another.*/
|
/** Combine Static Transform nodes that sit above one another.*/
|
||||||
class OSGUTIL_EXPORT CombineStaticTransformsVisitor : public BaseOptimizerVisitor
|
class OSGUTIL_EXPORT CombineStaticTransformsVisitor : public BaseOptimizerVisitor
|
||||||
|
@ -50,7 +50,7 @@ void Optimizer::reset()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static osg::ApplicationUsageProxy Optimizer_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_OPTIMIZER \"<type> [<type>]\"","OFF | DEFAULT | FLATTEN_STATIC_TRANSFORMS | REMOVE_REDUNDANT_NODES | COMBINE_ADJACENT_LODS | SHARE_DUPLICATE_STATE | MERGE_GEOMETRY | MERGE_GEODES | SPATIALIZE_GROUPS | COPY_SHARED_NODES | TRISTRIP_GEOMETRY | OPTIMIZE_TEXTURE_SETTINGS | REMOVE_LOADED_PROXY_NODES | TESSELLATE_GEOMETRY | CHECK_GEOMETRY | FLATTEN_BILLBOARDS | TEXTURE_ATLAS_BUILDER | STATIC_OBJECT_DETECTION");
|
static osg::ApplicationUsageProxy Optimizer_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_OPTIMIZER \"<type> [<type>]\"","OFF | DEFAULT | FLATTEN_STATIC_TRANSFORMS | FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS | REMOVE_REDUNDANT_NODES | COMBINE_ADJACENT_LODS | SHARE_DUPLICATE_STATE | MERGE_GEOMETRY | MERGE_GEODES | SPATIALIZE_GROUPS | COPY_SHARED_NODES | TRISTRIP_GEOMETRY | OPTIMIZE_TEXTURE_SETTINGS | REMOVE_LOADED_PROXY_NODES | TESSELLATE_GEOMETRY | CHECK_GEOMETRY | FLATTEN_BILLBOARDS | TEXTURE_ATLAS_BUILDER | STATIC_OBJECT_DETECTION");
|
||||||
|
|
||||||
void Optimizer::optimize(osg::Node* node)
|
void Optimizer::optimize(osg::Node* node)
|
||||||
{
|
{
|
||||||
@ -70,6 +70,9 @@ void Optimizer::optimize(osg::Node* node)
|
|||||||
if(str.find("~FLATTEN_STATIC_TRANSFORMS")!=std::string::npos) options ^= FLATTEN_STATIC_TRANSFORMS;
|
if(str.find("~FLATTEN_STATIC_TRANSFORMS")!=std::string::npos) options ^= FLATTEN_STATIC_TRANSFORMS;
|
||||||
else if(str.find("FLATTEN_STATIC_TRANSFORMS")!=std::string::npos) options |= FLATTEN_STATIC_TRANSFORMS;
|
else if(str.find("FLATTEN_STATIC_TRANSFORMS")!=std::string::npos) options |= FLATTEN_STATIC_TRANSFORMS;
|
||||||
|
|
||||||
|
if(str.find("~FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS")!=std::string::npos) options ^= FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS;
|
||||||
|
else if(str.find("FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS")!=std::string::npos) options |= FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS;
|
||||||
|
|
||||||
if(str.find("~REMOVE_REDUNDANT_NODES")!=std::string::npos) options ^= REMOVE_REDUNDANT_NODES;
|
if(str.find("~REMOVE_REDUNDANT_NODES")!=std::string::npos) options ^= REMOVE_REDUNDANT_NODES;
|
||||||
else if(str.find("REMOVE_REDUNDANT_NODES")!=std::string::npos) options |= REMOVE_REDUNDANT_NODES;
|
else if(str.find("REMOVE_REDUNDANT_NODES")!=std::string::npos) options |= REMOVE_REDUNDANT_NODES;
|
||||||
|
|
||||||
@ -236,6 +239,16 @@ void Optimizer::optimize(osg::Node* node, unsigned int options)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options & FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS)
|
||||||
|
{
|
||||||
|
osg::notify(osg::NOTICE)<<"Optimizer::optimize() doing FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS"<<std::endl;
|
||||||
|
|
||||||
|
// no combine any adjacent static transforms.
|
||||||
|
FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor fstdssv(this);
|
||||||
|
node->accept(fstdssv);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (options & MERGE_GEODES)
|
if (options & MERGE_GEODES)
|
||||||
{
|
{
|
||||||
osg::notify(osg::INFO)<<"Optimizer::optimize() doing MERGE_GEODES"<<std::endl;
|
osg::notify(osg::INFO)<<"Optimizer::optimize() doing MERGE_GEODES"<<std::endl;
|
||||||
@ -4244,3 +4257,253 @@ void Optimizer::StaticObjectDetectionVisitor::applyDrawable(osg::Drawable& drawa
|
|||||||
|
|
||||||
drawable.computeDataVariance();
|
drawable.computeDataVariance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Optimizer::FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor::reset()
|
||||||
|
{
|
||||||
|
_matrixStack.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Optimizer::FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor::apply(osg::Group& group)
|
||||||
|
{
|
||||||
|
// only continue if there is a parent
|
||||||
|
const unsigned int nodepathsize = _nodePath.size();
|
||||||
|
if(!_matrixStack.empty() && group.getNumParents() > 1 && nodepathsize > 1)
|
||||||
|
{
|
||||||
|
// copy this Group
|
||||||
|
osg::ref_ptr<osg::Object> new_obj = group.clone(osg::CopyOp::DEEP_COPY_NODES | osg::CopyOp::DEEP_COPY_DRAWABLES | osg::CopyOp::DEEP_COPY_ARRAYS);
|
||||||
|
osg::Group* new_group = dynamic_cast<osg::Group*>(new_obj.get());
|
||||||
|
|
||||||
|
// New Group should only be added to parent through which this Group
|
||||||
|
// was traversed, not to all parents of this Group.
|
||||||
|
osg::Group* parent_group = dynamic_cast<osg::Group*>(_nodePath[nodepathsize-2]);
|
||||||
|
if(parent_group)
|
||||||
|
{
|
||||||
|
parent_group->replaceChild(&group, new_group);
|
||||||
|
// traverse the new Group
|
||||||
|
traverse(*(new_group));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
osg::notify(osg::NOTICE) << "No parent for this Group" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// traverse original node
|
||||||
|
traverse(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Optimizer::FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor::apply(osg::Transform& transform)
|
||||||
|
{
|
||||||
|
bool pushed = false;
|
||||||
|
|
||||||
|
// only continue if there is a parent and this is a STATIC transform
|
||||||
|
const unsigned int nodepathsize = _nodePath.size();
|
||||||
|
if(transform.getDataVariance() == osg::Object::STATIC && nodepathsize > 1)
|
||||||
|
{
|
||||||
|
osg::Matrix matrix;
|
||||||
|
if(!_matrixStack.empty())
|
||||||
|
matrix = _matrixStack.back();
|
||||||
|
transform.computeLocalToWorldMatrix(matrix, this);
|
||||||
|
_matrixStack.push_back(matrix);
|
||||||
|
pushed = true;
|
||||||
|
|
||||||
|
// convert this Transform to a Group
|
||||||
|
osg::ref_ptr<osg::Group> group = new osg::Group(dynamic_cast<osg::Group&>(transform),
|
||||||
|
osg::CopyOp::DEEP_COPY_NODES | osg::CopyOp::DEEP_COPY_DRAWABLES | osg::CopyOp::DEEP_COPY_ARRAYS);
|
||||||
|
|
||||||
|
// New Group should only be added to parent through which this Transform
|
||||||
|
// was traversed, not to all parents of this Transform.
|
||||||
|
osg::Group* parent_group = dynamic_cast<osg::Group*>(_nodePath[nodepathsize-2]);
|
||||||
|
if(parent_group)
|
||||||
|
{
|
||||||
|
parent_group->replaceChild(&transform, group.get());
|
||||||
|
// traverse the new Group
|
||||||
|
traverse(*(group.get()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
osg::notify(osg::NOTICE) << "No parent for this Group" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// traverse original node
|
||||||
|
traverse(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pop matrix off of stack
|
||||||
|
if(pushed)
|
||||||
|
_matrixStack.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Optimizer::FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor::apply(osg::LOD& lod)
|
||||||
|
{
|
||||||
|
const unsigned int nodepathsize = _nodePath.size();
|
||||||
|
if(!_matrixStack.empty() && lod.getNumParents() > 1 && nodepathsize > 1)
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::LOD> new_lod = new osg::LOD(lod,
|
||||||
|
osg::CopyOp::DEEP_COPY_NODES | osg::CopyOp::DEEP_COPY_DRAWABLES | osg::CopyOp::DEEP_COPY_ARRAYS);
|
||||||
|
|
||||||
|
// New LOD should only be added to parent through which this LOD
|
||||||
|
// was traversed, not to all parents of this LOD.
|
||||||
|
osg::Group* parent_group = dynamic_cast<osg::Group*>(_nodePath[nodepathsize-2]);
|
||||||
|
if(parent_group)
|
||||||
|
{
|
||||||
|
parent_group->replaceChild(&lod, new_lod.get());
|
||||||
|
|
||||||
|
// move center point
|
||||||
|
if(!_matrixStack.empty())
|
||||||
|
new_lod->setCenter(new_lod->getCenter() * _matrixStack.back());
|
||||||
|
|
||||||
|
// traverse the new Group
|
||||||
|
traverse(*(new_lod.get()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
osg::notify(osg::NOTICE) << "No parent for this LOD" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// move center point
|
||||||
|
if(!_matrixStack.empty())
|
||||||
|
lod.setCenter(lod.getCenter() * _matrixStack.back());
|
||||||
|
|
||||||
|
traverse(lod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Optimizer::FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor::apply(osg::Geode& geode)
|
||||||
|
{
|
||||||
|
if(!_matrixStack.empty())
|
||||||
|
{
|
||||||
|
// If there is only one parent, just transform all vertices and normals
|
||||||
|
if(geode.getNumParents() == 1)
|
||||||
|
{
|
||||||
|
transformDrawables(geode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Else make a copy and then transform
|
||||||
|
const unsigned int nodepathsize = _nodePath.size();
|
||||||
|
if(nodepathsize > 1)
|
||||||
|
{
|
||||||
|
// convert this Transform to a Group
|
||||||
|
osg::ref_ptr<osg::Geode> new_geode = new osg::Geode(geode,
|
||||||
|
osg::CopyOp::DEEP_COPY_NODES | osg::CopyOp::DEEP_COPY_DRAWABLES | osg::CopyOp::DEEP_COPY_ARRAYS);
|
||||||
|
|
||||||
|
// New Group should only be added to parent through which this Transform
|
||||||
|
// was traversed, not to all parents of this Transform.
|
||||||
|
osg::Group* parent_group = dynamic_cast<osg::Group*>(_nodePath[nodepathsize-2]);
|
||||||
|
if(parent_group)
|
||||||
|
parent_group->replaceChild(&geode, new_geode.get());
|
||||||
|
else
|
||||||
|
osg::notify(osg::NOTICE) << "No parent for this Geode" << std::endl;
|
||||||
|
|
||||||
|
transformDrawables(*(new_geode.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Optimizer::FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor::apply(osg::Billboard& billboard)
|
||||||
|
{
|
||||||
|
if(!_matrixStack.empty())
|
||||||
|
{
|
||||||
|
// If there is only one parent, just transform this Billboard
|
||||||
|
if(billboard.getNumParents() == 1)
|
||||||
|
{
|
||||||
|
transformBillboard(billboard);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Else make a copy and then transform
|
||||||
|
const unsigned int nodepathsize = _nodePath.size();
|
||||||
|
if(nodepathsize > 1)
|
||||||
|
{
|
||||||
|
// convert this Transform to a Group
|
||||||
|
osg::ref_ptr<osg::Billboard> new_billboard = new osg::Billboard(billboard,
|
||||||
|
osg::CopyOp::DEEP_COPY_NODES | osg::CopyOp::DEEP_COPY_DRAWABLES | osg::CopyOp::DEEP_COPY_ARRAYS);
|
||||||
|
|
||||||
|
// New Billboard should only be added to parent through which this Billboard
|
||||||
|
// was traversed, not to all parents of this Billboard.
|
||||||
|
osg::Group* parent_group = dynamic_cast<osg::Group*>(_nodePath[nodepathsize-2]);
|
||||||
|
if(parent_group)
|
||||||
|
parent_group->replaceChild(&billboard, new_billboard.get());
|
||||||
|
else
|
||||||
|
osg::notify(osg::NOTICE) << "No parent for this Billboard" << std::endl;
|
||||||
|
|
||||||
|
transformBillboard(*(new_billboard.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Optimizer::FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor::transformDrawables(osg::Geode& geode)
|
||||||
|
{
|
||||||
|
for(unsigned int i=0; i<geode.getNumDrawables(); i++)
|
||||||
|
{
|
||||||
|
osg::Geometry* geometry = geode.getDrawable(i)->asGeometry();
|
||||||
|
if(geometry)
|
||||||
|
{
|
||||||
|
// transform all geometry
|
||||||
|
osg::Vec3Array* verts = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
|
||||||
|
if(verts)
|
||||||
|
{
|
||||||
|
for(unsigned int j=0; j<verts->size(); j++)
|
||||||
|
(*verts)[j] = (*verts)[j] * _matrixStack.back();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
osg::Vec4Array* verts = dynamic_cast<osg::Vec4Array*>(geometry->getVertexArray());
|
||||||
|
if(verts)
|
||||||
|
{
|
||||||
|
for(unsigned int j=0; j<verts->size(); j++)
|
||||||
|
(*verts)[j] = _matrixStack.back() * (*verts)[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
osg::Vec3Array* normals = dynamic_cast<osg::Vec3Array*>(geometry->getNormalArray());
|
||||||
|
if(normals)
|
||||||
|
{
|
||||||
|
for(unsigned int j=0; j<normals->size(); j++)
|
||||||
|
(*normals)[j] = osg::Matrix::transform3x3((*normals)[j], _matrixStack.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
geometry->dirtyBound();
|
||||||
|
geometry->dirtyDisplayList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
geode.dirtyBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Optimizer::FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor::transformBillboard(osg::Billboard& billboard)
|
||||||
|
{
|
||||||
|
osg::Vec3 axis = osg::Matrix::transform3x3(billboard.getAxis(), _matrixStack.back());
|
||||||
|
axis.normalize();
|
||||||
|
billboard.setAxis(axis);
|
||||||
|
|
||||||
|
osg::Vec3 normal = osg::Matrix::transform3x3(billboard.getNormal(), _matrixStack.back());
|
||||||
|
normal.normalize();
|
||||||
|
billboard.setNormal(normal);
|
||||||
|
|
||||||
|
for(unsigned int i=0; i<billboard.getNumDrawables(); i++)
|
||||||
|
billboard.setPosition(i, billboard.getPosition(i) * _matrixStack.back());
|
||||||
|
|
||||||
|
billboard.dirtyBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user