From Aurélien Chatelain, "the smoothing visitor did not handle shared arrays. It may leads to bad geometry arrays when a shared array is involved in the scene.

This submission adds shared array duplication (and moves the SharedArrayOptimizer declaration in MeshOptimizer to make it callable from the SmoothingVisitor)."

Submitted by Marc Helbling.
Edited by Robet Osfield to retain the usual OSG coding style.




git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@14639 16af8721-9629-0410-8352-f15c8da7e697
This commit is contained in:
Robert Osfield 2014-12-24 10:55:49 +00:00
parent 2870c12b03
commit a331680cec
3 changed files with 77 additions and 54 deletions

View File

@ -111,5 +111,15 @@ public:
void optimizeOrder();
void optimizeOrder(osg::Geometry& geom);
};
class OSGUTIL_EXPORT SharedArrayOptimizer
{
public:
void findDuplicatedUVs(const osg::Geometry& geometry);
void deduplicateUVs(osg::Geometry& geometry);
protected:
std::map<unsigned int, unsigned int> _deduplicateUvs;
}; // SharedArrayOptimizer
}
#endif

View File

@ -99,60 +99,6 @@ struct GeometryArrayGatherer
ArrayList _arrayList;
};
class SharedArrayOptimizer {
public:
void findDuplicatedUVs(const osg::Geometry& geometry)
{
_deduplicateUvs.clear();
// look for all channels that are shared only *within* the geometry
std::map<const osg::Array*, unsigned int> arrayPointerCounter;
for(unsigned int id = 0 ; id < geometry.getNumTexCoordArrays() ; ++ id) {
const osg::Array* channel = geometry.getTexCoordArray(id);
if(channel && channel->getNumElements()) {
if(arrayPointerCounter.find(channel) == arrayPointerCounter.end()) {
arrayPointerCounter[channel] = 1;
}
else {
arrayPointerCounter[channel] += 1;
}
}
}
std::map<const osg::Array*, unsigned int> references;
for(unsigned int id = 0 ; id != geometry.getNumTexCoordArrays() ; ++ id) {
const osg::Array* channel = geometry.getTexCoordArray(id);
// test if array is shared outside the geometry
if(channel && static_cast<unsigned int>(channel->referenceCount()) == arrayPointerCounter[channel]) {
std::map<const osg::Array*, unsigned int>::const_iterator reference = references.find(channel);
if(reference == references.end()) {
references[channel] = id;
}
else {
_deduplicateUvs[id] = reference->second;
}
}
}
}
void deduplicateUVs(osg::Geometry& geometry)
{
for(std::map<unsigned int, unsigned int>::const_iterator it_duplicate = _deduplicateUvs.begin() ;
it_duplicate != _deduplicateUvs.end() ; ++ it_duplicate) {
osg::Array* original = geometry.getTexCoordArray(it_duplicate->second);
geometry.setTexCoordArray(it_duplicate->first,
original,
(original ? original->getBinding() : osg::Array::BIND_UNDEFINED));
}
}
protected:
std::map<unsigned int, unsigned int> _deduplicateUvs;
};
// Compare vertices in a mesh using all their attributes. The vertices
// are identified by their index. Extracted from TriStripVisitor.cpp
struct VertexAttribComparitor : public GeometryArrayGatherer
@ -1244,4 +1190,61 @@ void VertexAccessOrderVisitor::optimizeOrder(Geometry& geom)
geom.dirtyDisplayList();
}
void SharedArrayOptimizer::findDuplicatedUVs(const osg::Geometry& geometry)
{
_deduplicateUvs.clear();
// look for all channels that are shared only *within* the geometry
std::map<const osg::Array*, unsigned int> arrayPointerCounter;
for(unsigned int id = 0 ; id < geometry.getNumTexCoordArrays() ; ++ id)
{
const osg::Array* channel = geometry.getTexCoordArray(id);
if(channel && channel->getNumElements())
{
if(arrayPointerCounter.find(channel) == arrayPointerCounter.end())
{
arrayPointerCounter[channel] = 1;
}
else
{
arrayPointerCounter[channel] += 1;
}
}
}
std::map<const osg::Array*, unsigned int> references;
for(unsigned int id = 0 ; id != geometry.getNumTexCoordArrays() ; ++ id)
{
const osg::Array* channel = geometry.getTexCoordArray(id);
// test if array is shared outside the geometry
if(channel && static_cast<unsigned int>(channel->referenceCount()) == arrayPointerCounter[channel])
{
std::map<const osg::Array*, unsigned int>::const_iterator reference = references.find(channel);
if(reference == references.end())
{
references[channel] = id;
}
else
{
_deduplicateUvs[id] = reference->second;
}
}
}
}
void SharedArrayOptimizer::deduplicateUVs(osg::Geometry& geometry)
{
for(std::map<unsigned int, unsigned int>::const_iterator it_duplicate = _deduplicateUvs.begin() ;
it_duplicate != _deduplicateUvs.end() ; ++ it_duplicate)
{
osg::Array* original = geometry.getTexCoordArray(it_duplicate->second);
geometry.setTexCoordArray(it_duplicate->first,
original,
(original ? original->getBinding() : osg::Array::BIND_UNDEFINED));
}
}
}

View File

@ -19,6 +19,7 @@
#include <stdio.h>
#include <list>
#include <set>
#include <osgUtil/MeshOptimizers>
using namespace osg;
@ -635,6 +636,13 @@ static void smooth_new(osg::Geometry& geom, double creaseAngle)
}
osg::TriangleIndexFunctor<FindSharpEdgesFunctor> fsef;
osgUtil::SharedArrayOptimizer sharedArrayOptimizer;
sharedArrayOptimizer.findDuplicatedUVs(geom);
// Duplicate shared arrays to avoid index errors during duplication
if (geom.containsSharedArrays()) geom.duplicateSharedArrays();
if (fsef.set(&geom, creaseAngle))
{
// look for normals that deviate too far
@ -660,6 +668,8 @@ static void smooth_new(osg::Geometry& geom, double creaseAngle)
}
}
sharedArrayOptimizer.deduplicateUVs(geom);
}
}