Beginning of crease angle support for SmoothingVisitor to all it duplicate vertices are creases

thus enabling separate normals for triangles adjacent to the creases.
This commit is contained in:
Robert Osfield
2010-07-30 19:39:38 +00:00
parent a71877bf2f
commit 075b1b769c
3 changed files with 276 additions and 18 deletions

View File

@@ -392,12 +392,18 @@ int main(int argc, char** argv)
if (!font) return 1;
OSG_NOTICE<<"Read font "<<fontFile<<" font="<<font.get()<<std::endl;
bool useTessellator = false;
bool useTessellator = true;
while(arguments.read("-t") || arguments.read("--tessellate")) { useTessellator = true; }
while(arguments.read("--no-tessellate")) { useTessellator = false; }
float thickness = 5.0;
while(arguments.read("--thickness",thickness)) {}
float creaseAngle = 10.0f;
while(arguments.read("--crease-angle",creaseAngle)) {}
OSG_NOTICE<<"creaseAngle="<<creaseAngle<<std::endl;
osg::ref_ptr<osg::Group> group = new osg::Group;
osg::Vec3 position;
@@ -432,7 +438,8 @@ int main(int argc, char** argv)
{
geode->addDrawable(bevel);
osgUtil::SmoothingVisitor smoother;
smoother.smooth(*bevel);
smoother.setCreaseAngle(osg::DegreesToRadians(creaseAngle));
geode->accept(smoother);
}
osg::Geometry* face = getGeometryComponent(face_and_bevel, false);

View File

@@ -34,11 +34,20 @@ class OSGUTIL_EXPORT SmoothingVisitor : public osg::NodeVisitor
virtual ~SmoothingVisitor();
/// smooth geoset by creating per vertex normals.
static void smooth(osg::Geometry& geoset);
static void smooth(osg::Geometry& geoset, double creaseAngle=osg::PI);
/// apply smoothing method to all geode geosets.
virtual void apply(osg::Geode& geode);
/// set the maximum angle, in radians, at which angle between adjacent triangles that normals are smoothed
/// for edges that greater the shared vertices are duplicated
void setCreaseAngle(double angle) { _creaseAngle = angle; }
double getCreaseAngle() const { return _creaseAngle; }
protected:
double _creaseAngle;
};
}

View File

@@ -11,6 +11,8 @@
* OpenSceneGraph Public License for more details.
*/
#include <osg/TriangleFunctor>
#include <osg/TriangleIndexFunctor>
#include <osg/io_utils>
#include <osgUtil/SmoothingVisitor>
@@ -22,6 +24,9 @@
using namespace osg;
using namespace osgUtil;
namespace Smoother
{
struct LessPtr
{
inline bool operator() (const osg::Vec3* lhs,const osg::Vec3* rhs) const
@@ -86,17 +91,9 @@ struct SmoothTriangleFunctor
}
};
SmoothingVisitor::SmoothingVisitor()
{
setTraversalMode(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN);
}
SmoothingVisitor::~SmoothingVisitor()
{
}
void SmoothingVisitor::smooth(osg::Geometry& geom)
static void smooth_old(osg::Geometry& geom)
{
OSG_INFO<<"smooth_old("<<&geom<<")"<<std::endl;
Geometry::PrimitiveSetList& primitives = geom.getPrimitiveSetList();
Geometry::PrimitiveSetList::iterator itr;
unsigned int numSurfacePrimitives=0;
@@ -118,12 +115,12 @@ void SmoothingVisitor::smooth(osg::Geometry& geom)
break;
}
}
if (!numSurfacePrimitives) return;
osg::Vec3Array *coords = dynamic_cast<osg::Vec3Array*>(geom.getVertexArray());
if (!coords || !coords->size()) return;
osg::Vec3Array *normals = new osg::Vec3Array(coords->size());
osg::Vec3Array::iterator nitr;
@@ -136,7 +133,7 @@ void SmoothingVisitor::smooth(osg::Geometry& geom)
TriangleFunctor<SmoothTriangleFunctor> stf;
stf.set(&(coords->front()),coords->size(),&(normals->front()));
geom.accept(stf);
for(nitr= normals->begin();
@@ -145,7 +142,6 @@ void SmoothingVisitor::smooth(osg::Geometry& geom)
{
nitr->normalize();
}
geom.setNormalArray( normals );
geom.setNormalIndices( geom.getVertexIndices() );
geom.setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
@@ -155,11 +151,257 @@ void SmoothingVisitor::smooth(osg::Geometry& geom)
}
struct SmoothTriangleIndexFunctor
{
SmoothTriangleIndexFunctor():
_vertices(0),
_normals(0)
{
}
bool set(osg::Vec3Array* vertices, osg::Vec3Array* normals)
{
_vertices = vertices;
_normals = normals;
if (!_vertices)
{
OSG_NOTICE<<"Warning: SmoothTriangleIndexFunctor::set(..) requires a valid vertex arrays."<<std::endl;
return false;
}
if (!_normals)
{
OSG_NOTICE<<"Warning: SmoothTriangleIndexFunctor::set(..) requires a valid normal arrays."<<std::endl;
return false;
}
for(osg::Vec3Array::iterator itr = _normals->begin();
itr != _normals->end();
++itr)
{
(*itr).set(0.0f,0.0f,0.0f);
}
return true;
}
void normalize()
{
if (!_normals) return;
for(osg::Vec3Array::iterator itr = _normals->begin();
itr != _normals->end();
++itr)
{
(*itr).normalize();
}
}
void operator() (unsigned int p1, unsigned int p2, unsigned int p3)
{
const osg::Vec3& v1 = (*_vertices)[p1];
const osg::Vec3& v2 = (*_vertices)[p2];
const osg::Vec3& v3 = (*_vertices)[p3];
osg::Vec3 normal( (v2-v1)^(v3-v1) );
normal.normalize();
(*_normals)[p1] += normal;
(*_normals)[p2] += normal;
(*_normals)[p3] += normal;
}
osg::Vec3Array* _vertices;
osg::Vec3Array* _normals;
};
struct FindSharpEdgesFunctor
{
FindSharpEdgesFunctor():
_vertices(0),
_normals(0),
_maxDeviationDotProduct(0.0f)
{
}
bool set(osg::Vec3Array* vertices, osg::Vec3Array* normals, float maxDeviationDotProduct)
{
_vertices = vertices;
_normals = normals;
_maxDeviationDotProduct = maxDeviationDotProduct;
if (!_vertices)
{
OSG_NOTICE<<"Warning: SmoothTriangleIndexFunctor::set(..) requires a valid vertex arrays."<<std::endl;
return false;
}
if (!_normals)
{
OSG_NOTICE<<"Warning: SmoothTriangleIndexFunctor::set(..) requires a valid normal arrays."<<std::endl;
return false;
}
OSG_NOTICE<<" _maxDeviationDotProduct = "<<_maxDeviationDotProduct<<std::endl;
_problemVertexVector.resize(_vertices->size());
return true;
}
void operator() (unsigned int p1, unsigned int p2, unsigned int p3)
{
const osg::Vec3& v1 = (*_vertices)[p1];
const osg::Vec3& v2 = (*_vertices)[p2];
const osg::Vec3& v3 = (*_vertices)[p3];
osg::Vec3 normal( (v2-v1)^(v3-v1) );
normal.normalize();
if (checkDeviation(p1, normal)) insertTriangle(p1, p1, p2, p3);
if (checkDeviation(p2, normal)) insertTriangle(p2, p1, p2, p3);
if (checkDeviation(p3, normal)) insertTriangle(p3, p1, p2, p3);
}
void insertTriangle(unsigned int p, unsigned int p1, unsigned int p2, unsigned int p3)
{
Triangle tri(p1,p2,p3);
if (!_problemVertexVector[p])
{
_problemVertexVector[p] = new ProblemVertex(p);
_problemVertexList.push_back(_problemVertexVector[p]);
}
_problemVertexVector[p]->_triangles.push_back(tri);
}
bool checkDeviation(unsigned int p, osg::Vec3& normal)
{
float deviation = normal * (*_normals)[p];
return (deviation < _maxDeviationDotProduct);
}
void listProblemVertices()
{
OSG_NOTICE<<"listProblemVertices() "<<_problemVertexList.size()<<std::endl;
for(ProblemVertexList::iterator itr = _problemVertexList.begin();
itr != _problemVertexList.end();
++itr)
{
ProblemVertex* pv = itr->get();
OSG_NOTICE<<" pv._point = "<<pv->_point<<" triangles "<<pv->_triangles.size()<<std::endl;
}
}
struct Triangle
{
Triangle(unsigned int p1, unsigned int p2, unsigned int p3):
_p1(p1), _p2(p2), _p3(p3) {}
Triangle(const Triangle& tri):
_p1(tri._p1), _p2(tri._p2), _p3(tri._p3) {}
Triangle& operator = (const Triangle& tri)
{
_p1 = tri._p1;
_p2 = tri._p2;
_p3 = tri._p3;
return *this;
}
unsigned int _p1;
unsigned int _p2;
unsigned int _p3;
};
struct ProblemVertex : public osg::Referenced
{
ProblemVertex(unsigned int p):
_point(p) {}
typedef std::list<Triangle> Triangles;
unsigned int _point;
Triangles _triangles;
};
typedef std::vector< osg::ref_ptr<ProblemVertex> > ProblemVertexVector;
typedef std::list< osg::ref_ptr<ProblemVertex> > ProblemVertexList;
osg::Vec3Array* _vertices;
osg::Vec3Array* _normals;
float _maxDeviationDotProduct;
ProblemVertexVector _problemVertexVector;
ProblemVertexList _problemVertexList;
};
static void smooth_new(osg::Geometry& geom, double creaseAngle)
{
OSG_NOTICE<<"smooth_new("<<&geom<<", "<<osg::RadiansToDegrees(creaseAngle)<<")"<<std::endl;
osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geom.getVertexArray());
if (!vertices) return;
osg::Vec3Array* normals = dynamic_cast<osg::Vec3Array*>(geom.getNormalArray());
if (!normals)
{
normals = new osg::Vec3Array(vertices->size());
geom.setNormalArray(normals);
geom.setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
}
osg::TriangleIndexFunctor<SmoothTriangleIndexFunctor> stif;
if (stif.set(vertices, normals))
{
// accumulate all the normals
geom.accept(stif);
// normalize the normals
stif.normalize();
}
osg::TriangleIndexFunctor<FindSharpEdgesFunctor> fsef;
if (fsef.set(vertices, normals, cos(creaseAngle*0.5)))
{
// look normals that deviate too far
geom.accept(fsef);
fsef.listProblemVertices();
}
}
}
SmoothingVisitor::SmoothingVisitor():
_creaseAngle(osg::PI)
{
setTraversalMode(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN);
}
SmoothingVisitor::~SmoothingVisitor()
{
}
void SmoothingVisitor::smooth(osg::Geometry& geom, double creaseAngle)
{
if (creaseAngle==osg::PI)
{
Smoother::smooth_old(geom);
}
else
{
Smoother::smooth_new(geom, creaseAngle);
}
}
void SmoothingVisitor::apply(osg::Geode& geode)
{
for(unsigned int i = 0; i < geode.getNumDrawables(); i++ )
{
osg::Geometry* geom = dynamic_cast<osg::Geometry*>(geode.getDrawable(i));
if (geom) smooth(*geom);
if (geom) smooth(*geom, _creaseAngle);
}
}