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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user