TriangleMeshSmoother::TriangleMeshSmoother(osg::Geometry& geometry, float creaseAngle, bool comparePosition, int mode):
    _geometry(geometry),
    _creaseAngle(creaseAngle),
    _graph(0),
    _mode(mode)
{
    if(!_geometry.getVertexArray() || !_geometry.getVertexArray()->getNumElements()) {
        return;
    }

    osgUtil::SharedArrayOptimizer deduplicator;
    deduplicator.findDuplicatedUVs(geometry);

    // duplicate shared arrays as it isn't safe to duplicate vertices when arrays are shared.
    if (geometry.containsSharedArrays()) {
        geometry.duplicateSharedArrays();
    }

    if(!_geometry.getNormalArray() || _geometry.getNormalArray()->getNumElements() != _geometry.getVertexArray()->getNumElements()) {
        _geometry.setNormalArray(new osg::Vec3Array(_geometry.getVertexArray()->getNumElements()), osg::Array::BIND_PER_VERTEX);
    }

    // build a unifier to consider deduplicated vertex indices
    _graph = new TriangleMeshGraph(_geometry, comparePosition);

    unsigned int nbTriangles = 0;
    for(unsigned int i = 0 ; i < _geometry.getNumPrimitiveSets() ; ++ i) {
        osg::PrimitiveSet* primitive = _geometry.getPrimitiveSet(i);

        if(!primitive || !primitive->getNumIndices()) {
            continue;
        }
        else if(primitive->getMode() > osg::PrimitiveSet::TRIANGLES) {
            OSG_INFO << "[smoother] Cannot smooth geometry '" << _geometry.getName()
                        << "' due to not tessellated primitives" << std::endl;
            return;
        }
        else if(primitive->getMode() == osg::PrimitiveSet::TRIANGLES) {
            nbTriangles += primitive->getNumIndices() / 3;
        }
    }
    _triangles.reserve(nbTriangles);

    // collect all buffers that are BIND_PER_VERTEX for eventual vertex duplication
    addArray(_geometry.getVertexArray());
    addArray(_geometry.getColorArray());
    addArray(_geometry.getSecondaryColorArray());
    addArray(_geometry.getFogCoordArray());
    for(unsigned int i = 0; i < _geometry.getNumTexCoordArrays(); ++ i) {
        addArray(_geometry.getTexCoordArray(i));
    }
    for(unsigned int i = 0; i < _geometry.getNumVertexAttribArrays(); ++ i) {
        addArray(_geometry.getVertexAttribArray(i));
    }

    switch(_mode) {
        case recompute:
            computeVertexNormals();
            break;
        case smooth_all:
            smoothVertexNormals(true, true);
            break;
        case smooth_flipped:
            smoothVertexNormals(true, false);
            break;
        case diagnose:
            smoothVertexNormals(false, false);
            break;
    };

    // deduplicate UVs array that were only shared within the geometry
    deduplicator.deduplicateUVs(geometry);
}
示例#2
0
void IndexMeshVisitor::apply(osg::Geometry& geom) {
    // TODO: this is deprecated
    if (geom.getNormalBinding() == osg::Geometry::BIND_PER_PRIMITIVE_SET) return;
    if (geom.getColorBinding() == osg::Geometry::BIND_PER_PRIMITIVE_SET) return;
    if (geom.getSecondaryColorBinding() == osg::Geometry::BIND_PER_PRIMITIVE_SET) return;
    if (geom.getFogCoordBinding() == osg::Geometry::BIND_PER_PRIMITIVE_SET) return;

    // no point optimizing if we don't have enough vertices.
    if (!geom.getVertexArray() || geom.getVertexArray()->getNumElements() < 3) return;


    osgUtil::SharedArrayOptimizer deduplicator;
    deduplicator.findDuplicatedUVs(geom);

    // duplicate shared arrays as it isn't safe to rearrange vertices when arrays are shared.
    if (geom.containsSharedArrays()) {
        geom.duplicateSharedArrays();
    }

    osg::Geometry::PrimitiveSetList& primitives = geom.getPrimitiveSetList();
    osg::Geometry::PrimitiveSetList::iterator itr;

    osg::Geometry::PrimitiveSetList new_primitives;
    new_primitives.reserve(primitives.size());

    // compute duplicate vertices
    typedef std::vector<unsigned int> IndexList;
    unsigned int numVertices = geom.getVertexArray()->getNumElements();
    IndexList indices(numVertices);
    unsigned int i, j;
    for(i = 0 ; i < numVertices ; ++ i) {
        indices[i] = i;
    }

    VertexAttribComparitor arrayComparitor(geom);
    std::sort(indices.begin(), indices.end(), arrayComparitor);

    unsigned int lastUnique = 0;
    unsigned int numUnique = 1;
    for(i = 1 ; i < numVertices ; ++ i) {
        if (arrayComparitor.compare(indices[lastUnique], indices[i]) != 0) {
            lastUnique = i;
            ++ numUnique;
        }
    }

    IndexList remapDuplicatesToOrignals(numVertices);
    lastUnique = 0;
    for(i = 1 ; i < numVertices ; ++ i) {
        if (arrayComparitor.compare(indices[lastUnique],indices[i]) != 0) {
            // found a new vertex entry, so previous run of duplicates needs
            // to be put together.
            unsigned int min_index = indices[lastUnique];
            for(j = lastUnique + 1 ; j < i ; ++ j) {
                min_index = osg::minimum(min_index, indices[j]);
            }
            for(j = lastUnique ; j < i ; ++ j) {
                remapDuplicatesToOrignals[indices[j]] = min_index;
            }
            lastUnique = i;
        }
    }

    unsigned int min_index = indices[lastUnique];
    for(j = lastUnique + 1 ; j < i ; ++ j) {
        min_index = osg::minimum(min_index, indices[j]);
    }
    for(j = lastUnique ; j < i ; ++ j) {
        remapDuplicatesToOrignals[indices[j]] = min_index;
    }

    // copy the arrays.
    IndexList finalMapping(numVertices);
    IndexList copyMapping;
    copyMapping.reserve(numUnique);
    unsigned int currentIndex = 0;
    for(i = 0 ; i < numVertices ; ++ i) {
        if (remapDuplicatesToOrignals[i] == i) {
            finalMapping[i] = currentIndex;
            copyMapping.push_back(i);
            currentIndex++;
        }
        else {
            finalMapping[i] = finalMapping[remapDuplicatesToOrignals[i]];
        }
    }

    // remap any shared vertex attributes
    RemapArray ra(copyMapping);
    arrayComparitor.accept(ra);

    // triangulate faces
    {
        TriangleIndexor ti;
        ti._maxIndex = numVertices;
        ti._remapping = finalMapping;

        for(itr = primitives.begin() ; itr != primitives.end() ; ++ itr) {
            (*itr)->accept(ti);
        }

        addDrawElements(ti._indices, osg::PrimitiveSet::TRIANGLES, new_primitives);
    }

    // line-ify line-type primitives
    {
        LineIndexor li, wi; // lines and wireframes
        li._maxIndex = numVertices;
        wi._maxIndex = numVertices;
        li._remapping = finalMapping;
        wi._remapping = finalMapping;

        for(itr = primitives.begin() ; itr != primitives.end() ; ++ itr) {
            bool isWireframe = false;
            if((*itr)->getUserValue("wireframe", isWireframe) && isWireframe) {
                (*itr)->accept(wi);
            }
            else {
                (*itr)->accept(li);
            }
        }
        addDrawElements(li._indices, osg::PrimitiveSet::LINES, new_primitives);
        addDrawElements(wi._indices, osg::PrimitiveSet::LINES, new_primitives, "wireframe");
    }

    // adds points primitives
    {
        IndexList points;
        for(itr = primitives.begin() ; itr != primitives.end() ; ++ itr) {
            if((*itr) && (*itr)->getMode() == osg::PrimitiveSet::POINTS) {
                for(unsigned int k = 0 ; k < (*itr)->getNumIndices() ; ++ k) {
                    points.push_back(finalMapping[(*itr)->index(k)]);
                }
            }
        }
        addDrawElements(points, osg::PrimitiveSet::POINTS, new_primitives);
    }

    geom.setPrimitiveSetList(new_primitives);
    deduplicator.deduplicateUVs(geom);
    setProcessed(&geom);
}