Added support for using the error metric to guide the simplficiation process
This commit is contained in:
parent
45179b8868
commit
061244056d
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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();
|
||||||
edge->setErrorMetric( computeErrorMetric( edge, edge->_proposedPoint.get()));
|
|
||||||
|
if (edge->getMaxNormalDeviationOnEdgeCollapse()<=1.0f && !edge->isAdjacentToBoundary())
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
@ -145,9 +147,13 @@ public:
|
|||||||
{
|
{
|
||||||
Edge* edge = itr->get();
|
Edge* edge = itr->get();
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user