Added support for using the error metric to guide the simplficiation process

This commit is contained in:
Robert Osfield 2004-04-19 23:08:30 +00:00
parent 45179b8868
commit 061244056d
4 changed files with 87 additions and 78 deletions

View File

@ -28,11 +28,47 @@ class OSGUTIL_EXPORT Simplifier : public osg::NodeVisitor
{ {
public: public:
Simplifier(float sampleRatio=0.5f); Simplifier(float sampleRatio=1.0f, float maximumError=0.0f);
void setSampleRatio(float sampleRatio) { _sampleRatio = sampleRatio; } void setSampleRatio(float sampleRatio) { _sampleRatio = sampleRatio; }
float getSampleRatio() const { return _sampleRatio; } float getSampleRatio() const { return _sampleRatio; }
void setMaximumError(float error) { _maximumError = error; }
float getMaximumError() const { return _maximumError; }
class ContinueSimplificationCallback : public osg::Referenced
{
public:
/** return true if mesh should be continued to be simplified, return false to stop simplification.*/
virtual bool continueSimplification(const Simplifier& simplifier, float nextError, unsigned int numOriginalPrimitives, unsigned int numRemainingPrimitives) const
{
return simplifier.continueSimplificationImplementation(nextError, numOriginalPrimitives, numRemainingPrimitives);
}
protected:
virtual ~ContinueSimplificationCallback() {}
};
void setContinueSimplificationCallback(ContinueSimplificationCallback* cb) { _continueSimplificationCallback = cb; }
ContinueSimplificationCallback* getContinueSimplificationCallback() { return _continueSimplificationCallback.get(); }
const ContinueSimplificationCallback* getContinueSimplificationCallback() const { return _continueSimplificationCallback.get(); }
bool continueSimplification(float nextError, unsigned int numOriginalPrimitives, unsigned int numRemainingPrimitives) const
{
if (_continueSimplificationCallback.valid()) return _continueSimplificationCallback->continueSimplification(*this, nextError, numOriginalPrimitives, numRemainingPrimitives);
else return continueSimplificationImplementation(nextError, numOriginalPrimitives, numRemainingPrimitives);
}
virtual bool continueSimplificationImplementation(float nextError, unsigned int numOriginalPrimitives, unsigned int numRemainingPrimitives) const
{
if (nextError<=getMaximumError()) return true;
return (float)numRemainingPrimitives > (float)numOriginalPrimitives * getSampleRatio();
}
virtual void apply(osg::Geode& geode) virtual void apply(osg::Geode& geode)
{ {
for(unsigned int i=0;i<geode.getNumDrawables();++i) for(unsigned int i=0;i<geode.getNumDrawables();++i)
@ -40,20 +76,21 @@ class OSGUTIL_EXPORT Simplifier : public osg::NodeVisitor
osg::Geometry* geometry = geode.getDrawable(i)->asGeometry(); osg::Geometry* geometry = geode.getDrawable(i)->asGeometry();
if (geometry) if (geometry)
{ {
simplify(*geometry,_sampleRatio); simplify(*geometry);
} }
} }
} }
/** simply the geometry to defined ratio of original size.*/ /** simply the geometry to defined ratio of original size.*/
void simplify(osg::Geometry& geometry, float sampleRatio); void simplify(osg::Geometry& geometry);
void simplify(osg::Geometry& geometry, unsigned int targetNumberOfTriangles);
protected: protected:
float _sampleRatio; float _sampleRatio;
float _maximumError;
osg::ref_ptr<ContinueSimplificationCallback> _continueSimplificationCallback;
}; };

View File

@ -2185,8 +2185,10 @@ osg::Node* DataSet::DestinationTile::createPolygonal()
} }
#if 1 #if 1
osgUtil::Simplifier simplifier; osgUtil::Simplifier simplifier(1.0f,geometry->getBound().radius()/2000.0f);
simplifier.simplify(*geometry,0.5f); // this will replace the normal vector with a new one // osgUtil::Simplifier simplifier(1.0f,1.0f);
simplifier.simplify(*geometry); // this will replace the normal vector with a new one
#endif #endif
osg::Geode* geode = new osg::Geode; osg::Geode* geode = new osg::Geode;

View File

@ -28,7 +28,6 @@
#include <osgUtil/TransformAttributeFunctor> #include <osgUtil/TransformAttributeFunctor>
#include <osgUtil/TriStripVisitor> #include <osgUtil/TriStripVisitor>
#include <osgUtil/Tesselator> #include <osgUtil/Tesselator>
#include <osgUtil/Simplifier>
#include <typeinfo> #include <typeinfo>
#include <algorithm> #include <algorithm>
@ -216,11 +215,7 @@ void Optimizer::optimize(osg::Node* node, unsigned int options)
node->accept(tsv); node->accept(tsv);
tsv.stripify(); tsv.stripify();
} }
#if 0
// simplify geometry
osgUtil::Simplifier simplifier;
node->accept(simplifier);
#endif
} }

View File

@ -43,15 +43,13 @@ public:
struct Point; struct Point;
EdgeCollapse(): EdgeCollapse() {}
_targetNumTriangles(0) {}
~EdgeCollapse() {} ~EdgeCollapse() {}
void setGeometry(osg::Geometry* geometry); void setGeometry(osg::Geometry* geometry);
osg::Geometry* getGeometry() { return _geometry; } osg::Geometry* getGeometry() { return _geometry; }
void setTargetNumOfTriangles(unsigned int num) { _targetNumTriangles = num; }
unsigned int getNumOfTriangles() { return _triangleSet.size(); } unsigned int getNumOfTriangles() { return _triangleSet.size(); }
Point* computeInterpolatedPoint(Edge* edge,float r) const Point* computeInterpolatedPoint(Edge* edge,float r) const
@ -126,7 +124,11 @@ public:
edge->_proposedPoint = computeOptimalPoint(edge); edge->_proposedPoint = computeOptimalPoint(edge);
edge->updateMaxNormalDeviationOnEdgeCollapse(); edge->updateMaxNormalDeviationOnEdgeCollapse();
if (edge->getMaxNormalDeviationOnEdgeCollapse()<=1.0f && !edge->isAdjacentToBoundary())
edge->setErrorMetric( computeErrorMetric( edge, edge->_proposedPoint.get())); edge->setErrorMetric( computeErrorMetric( edge, edge->_proposedPoint.get()));
else
edge->setErrorMetric( FLT_MAX );
_edgeSet.insert(keep_local_reference_to_edge); _edgeSet.insert(keep_local_reference_to_edge);
} }
@ -147,7 +149,11 @@ public:
edge->_proposedPoint = computeOptimalPoint(edge); edge->_proposedPoint = computeOptimalPoint(edge);
edge->updateMaxNormalDeviationOnEdgeCollapse(); edge->updateMaxNormalDeviationOnEdgeCollapse();
if (edge->getMaxNormalDeviationOnEdgeCollapse()<=1.0f && !edge->isAdjacentToBoundary())
edge->setErrorMetric( computeErrorMetric( edge, edge->_proposedPoint.get())); edge->setErrorMetric( computeErrorMetric( edge, edge->_proposedPoint.get()));
else
edge->setErrorMetric( FLT_MAX );
_edgeSet.insert(edge); _edgeSet.insert(edge);
} }
@ -163,7 +169,7 @@ public:
{ {
Edge* edge = const_cast<Edge*>(itr->get()); Edge* edge = const_cast<Edge*>(itr->get());
if (!edge->isAdjacentToBoundary()) // if (!edge->isAdjacentToBoundary())
{ {
osg::ref_ptr<Point> pNew = edge->_proposedPoint.valid()? edge->_proposedPoint : computeInterpolatedPoint(edge,0.5f); osg::ref_ptr<Point> pNew = edge->_proposedPoint.valid()? edge->_proposedPoint : computeInterpolatedPoint(edge,0.5f);
if (collapseEdge(edge,pNew.get())) return true; if (collapseEdge(edge,pNew.get())) return true;
@ -683,7 +689,7 @@ public:
if (edge->getMaxNormalDeviationOnEdgeCollapse()>1.0) if (edge->getMaxNormalDeviationOnEdgeCollapse()>1.0)
{ {
std::cout<<"collapseEdge("<<edge<<") refused due to edge->getMaxNormalDeviationOnEdgeCollapse() = "<<edge->getMaxNormalDeviationOnEdgeCollapse()<<std::endl; // std::cout<<"collapseEdge("<<edge<<") refused due to edge->getMaxNormalDeviationOnEdgeCollapse() = "<<edge->getMaxNormalDeviationOnEdgeCollapse()<<std::endl;
return false; return false;
} }
else else
@ -959,14 +965,13 @@ public:
return numErrors; return numErrors;
} }
protected: //protected:
typedef std::vector< osg::ref_ptr<osg::Array> > ArrayList; typedef std::vector< osg::ref_ptr<osg::Array> > ArrayList;
osg::Geometry* _geometry; osg::Geometry* _geometry;
ArrayList _arrayList; ArrayList _arrayList;
unsigned int _targetNumTriangles;
EdgeSet _edgeSet; EdgeSet _edgeSet;
TriangleSet _triangleSet; TriangleSet _triangleSet;
PointSet _pointSet; PointSet _pointSet;
@ -1341,41 +1346,6 @@ class CopyPointsToVertexArrayVisitor : public osg::ArrayVisitor
void EdgeCollapse::copyBackToGeometry() void EdgeCollapse::copyBackToGeometry()
{ {
#if 1
updateErrorMetricForAllEdges();
#endif
std::cout<<"******* BEFORE EDGE COLLAPSE ********"<<_triangleSet.size()<<std::endl;
std::cout<<"Number of triangle errors before edge collapse= "<<testAllTriangles()<<std::endl;
std::cout<<"Number of edge errors before edge collapse= "<<testAllEdges()<<std::endl;
std::cout<<"Number of point errors before edge collapse= "<<testAllPoints()<<std::endl;
std::cout<<"Number of triangles= "<<_triangleSet.size()<<std::endl;
std::cout<<"Number of points= "<<_pointSet.size()<<std::endl;
std::cout<<"Number of edges= "<<_edgeSet.size()<<std::endl;
std::cout<<"Number of boundary edges= "<<computeNumBoundaryEdges()<<std::endl;
while (_triangleSet.size()>_targetNumTriangles)
{
unsigned int numBefore = computeNumBoundaryEdges();
bool result = collapseMinimumErrorEdge();
unsigned int numAfter = computeNumBoundaryEdges();
if (numBefore!=numAfter)
{
std::cout<<"After collapse edge, boundary edges changes from "<<numBefore<<" to "<<numAfter<<std::endl;
}
if (!result) break;
}
std::cout<<"******* AFTER EDGE COLLAPSE *********"<<_triangleSet.size()<<std::endl;
std::cout<<"Number of triangle errors after edge collapse= "<<testAllTriangles()<<std::endl;
std::cout<<"Number of edge errors before edge collapse= "<<testAllEdges()<<std::endl;
std::cout<<"Number of point errors after edge collapse= "<<testAllPoints()<<std::endl;
std::cout<<"Number of triangles= "<<_triangleSet.size()<<std::endl;
std::cout<<"Number of points= "<<_pointSet.size()<<std::endl;
std::cout<<"Number of edges= "<<_edgeSet.size()<<std::endl;
std::cout<<"Number of boundary edges= "<<computeNumBoundaryEdges()<<std::endl;
// rebuild the _pointList from the _pointSet // rebuild the _pointList from the _pointSet
_originalPointList.clear(); _originalPointList.clear();
@ -1442,37 +1412,42 @@ void EdgeCollapse::copyBackToGeometry()
} }
Simplifier::Simplifier(float sampleRatio): Simplifier::Simplifier(float sampleRatio, float maximumError):
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_sampleRatio(sampleRatio) _sampleRatio(sampleRatio),
_maximumError(maximumError)
{ {
} }
void Simplifier::simplify(osg::Geometry& geometry, float sampleRatio) void Simplifier::simplify(osg::Geometry& geometry)
{ {
std::cout<<"++++++++++++++simplifier************"<<std::endl; std::cout<<"++++++++++++++simplifier************"<<std::endl;
EdgeCollapse ec; EdgeCollapse ec;
ec.setGeometry(&geometry); ec.setGeometry(&geometry);
ec.setTargetNumOfTriangles((unsigned int)(sampleRatio*(float)ec.getNumOfTriangles())); ec.updateErrorMetricForAllEdges();
unsigned int numOriginalPrimitives = ec._triangleSet.size();
while (!ec._edgeSet.empty() &&
continueSimplification((*ec._edgeSet.begin())->getErrorMetric() , numOriginalPrimitives, ec._triangleSet.size()) &&
ec.collapseMinimumErrorEdge())
{
std::cout<<"Collapsed edge ec._triangleSet.size()="<<ec._triangleSet.size()<<" error="<<(*ec._edgeSet.begin())->getErrorMetric()<<" vs "<<getMaximumError()<<std::endl;
}
std::cout<<"******* AFTER EDGE COLLAPSE *********"<<ec._triangleSet.size()<<std::endl;
std::cout<<"Number of triangle errors after edge collapse= "<<ec.testAllTriangles()<<std::endl;
std::cout<<"Number of edge errors before edge collapse= "<<ec.testAllEdges()<<std::endl;
std::cout<<"Number of point errors after edge collapse= "<<ec.testAllPoints()<<std::endl;
std::cout<<"Number of triangles= "<<ec._triangleSet.size()<<std::endl;
std::cout<<"Number of points= "<<ec._pointSet.size()<<std::endl;
std::cout<<"Number of edges= "<<ec._edgeSet.size()<<std::endl;
std::cout<<"Number of boundary edges= "<<ec.computeNumBoundaryEdges()<<std::endl;
//while (ec.collapseMinimumErrorEdge()) {}
ec.copyBackToGeometry(); ec.copyBackToGeometry();
} }
void Simplifier::simplify(osg::Geometry& geometry, unsigned int targetNumberOfTriangles)
{
std::cout<<"------------simplifier************"<<std::endl;
EdgeCollapse ec;
ec.setGeometry(&geometry);
ec.setTargetNumOfTriangles(targetNumberOfTriangles);
//while (ec.collapseMinimumErrorEdge()) {}
ec.copyBackToGeometry();
}