Hi, Here a pseudo loader to split big models to bunch of model < 65536 vertexes, it's useful when working with gl es 2.0.
example: osgconv bigmodel.osg.split manymodels.osg I use it for http://showwebgl.com website Cedric -- Provide OpenGL, WebGL and OpenSceneGraph services +33 659 598 614 Cedric Pinson mailto:[email protected] http://plopbyte.com
/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson
*
* This application is open source and may be redistributed and/or modified
* freely and without restriction, both in commercial and non commercial
* applications, as long as this copyright notice is maintained.
*
* This application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#include <osg/NodeVisitor>
#include <osg/Texture2D>
#include <osg/StateSet>
#include <osg/Geode>
#include <osg/Array>
#include <osg/TriangleFunctor>
#include <osgUtil/MeshOptimizers>
#include <string>
#include <osgDB/ReadFile>
#include <osgDB/ReaderWriter>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/Registry>
typedef std::vector<osg::ref_ptr<osg::Geometry> > GeometryList;
struct FunctionCopy {
void operator()(osg::Array* src, unsigned int index, osg::Array* dst) {
osg::Vec3Array* vec3Array= dynamic_cast<osg::Vec3Array*>(src);
if (vec3Array) {
osg::Vec3Array* vec3ArrayDst = dynamic_cast<osg::Vec3Array*>(dst);
vec3ArrayDst->push_back((*vec3Array)[index]);
return;
}
osg::Vec2Array* vec2Array= dynamic_cast<osg::Vec2Array*>(src);
if (vec2Array) {
osg::Vec2Array* vec2ArrayDst = dynamic_cast<osg::Vec2Array*>(dst);
vec2ArrayDst->push_back((*vec2Array)[index]);
return;
}
osg::Vec4Array* vec4Array= dynamic_cast<osg::Vec4Array*>(src);
if (vec2Array) {
osg::Vec4Array* vec4ArrayDst = dynamic_cast<osg::Vec4Array*>(dst);
vec4ArrayDst->push_back((*vec4Array)[index]);
return;
}
}
};
struct ConvertToBindPerVertex {
template <class T> void convert(T& array, osg::Geometry::AttributeBinding fromBinding, osg::Geometry::PrimitiveSetList& primitives, unsigned int size)
{
osg::ref_ptr<T> result = new T();
for (unsigned int p = 0; p < primitives.size(); p++) {
switch ( primitives[p]->getMode() ) {
case osg::PrimitiveSet::POINTS:
break;
case osg::PrimitiveSet::LINES:
switch(fromBinding) {
case osg::Geometry::BIND_OFF:
case osg::Geometry::BIND_PER_VERTEX:
break;
case osg::Geometry::BIND_OVERALL:
{
for (unsigned int i = 0; i < primitives[p]->getNumIndices(); i++)
result->push_back(array[0]);
}
break;
case osg::Geometry::BIND_PER_PRIMITIVE_SET:
{
unsigned int nb = primitives[p]->getNumIndices();
for (unsigned int i = 0; i < nb; i++)
result->push_back(array[p]);
}
break;
case osg::Geometry::BIND_PER_PRIMITIVE:
{
unsigned int nb = primitives[p]->getNumPrimitives();
for (unsigned int i = 0; i < nb; i++) {
result->push_back(array[i]);
result->push_back(array[i]);
}
}
break;
}
break;
case osg::PrimitiveSet::TRIANGLES:
switch(fromBinding) {
case osg::Geometry::BIND_OFF:
case osg::Geometry::BIND_PER_VERTEX:
break;
case osg::Geometry::BIND_OVERALL:
{
for (unsigned int i = 0; i < primitives[p]->getNumIndices(); i++)
result->push_back(array[0]);
}
break;
case osg::Geometry::BIND_PER_PRIMITIVE_SET:
{
unsigned int nb = primitives[p]->getNumIndices();
for (unsigned int i = 0; i < nb; i++)
result->push_back(array[p]);
}
break;
case osg::Geometry::BIND_PER_PRIMITIVE:
{
unsigned int nb = primitives[p]->getNumPrimitives();
for (unsigned int i = 0; i < nb; i++) {
result->push_back(array[i]);
result->push_back(array[i]);
result->push_back(array[i]);
}
}
break;
}
break;
}
}
array = *result;
}
void operator()(osg::Array* src, osg::Geometry::AttributeBinding fromBinding, osg::Geometry::PrimitiveSetList& primitives, unsigned int size) {
osg::Vec3Array* vec3Array= dynamic_cast<osg::Vec3Array*>(src);
if (vec3Array) {
convert(*vec3Array, fromBinding, primitives, size);
return;
}
osg::Vec2Array* vec2Array= dynamic_cast<osg::Vec2Array*>(src);
if (vec2Array) {
convert(*vec2Array, fromBinding, primitives, size);
return;
}
osg::Vec4Array* vec4Array= dynamic_cast<osg::Vec4Array*>(src);
if (vec4Array) {
convert(*vec4Array, fromBinding, primitives, size);
return;
}
}
};
struct ArrayList {
osg::ref_ptr<osg::Array> _vertexes;
osg::ref_ptr<osg::Array> _normals;
osg::ref_ptr<osg::Array> _colors;
osg::ref_ptr<osg::Array> _secondaryColors;
osg::ref_ptr<osg::Array> _fogCoords;
std::vector<osg::ref_ptr<osg::Array> > _texCoordArrays;
ArrayList() {}
ArrayList(osg::Geometry& geometry) {
_vertexes = geometry.getVertexArray();
_normals = geometry.getNormalArray();
_colors = geometry.getColorArray();
_secondaryColors = geometry.getSecondaryColorArray();
_fogCoords = geometry.getFogCoordArray();
_texCoordArrays.resize(geometry.getNumTexCoordArrays());
for(unsigned int i=0;i<geometry.getNumTexCoordArrays();++i)
_texCoordArrays[i] = geometry.getTexCoordArray(i);
}
unsigned int append(unsigned int index, ArrayList& dst) {
if (_vertexes.valid()) {
FunctionCopy()(_vertexes.get(), index, dst._vertexes.get());
}
if (_normals.valid()) {
FunctionCopy()(_normals.get(), index, dst._normals.get());
}
if (_colors.valid()) {
FunctionCopy()(_colors.get(), index, dst._colors.get());
}
if (_secondaryColors.valid()) {
FunctionCopy()(_secondaryColors.get(), index, dst._secondaryColors.get());
}
if (_fogCoords.valid()) {
FunctionCopy()(_fogCoords.get(), index, dst._fogCoords.get());
}
for (unsigned int i = 0; i < _texCoordArrays.size(); i++)
if (_texCoordArrays[i].valid()) {
FunctionCopy()(_texCoordArrays[i].get(), index, dst._texCoordArrays[i].get());
}
return dst._vertexes->getNumElements()-1;
}
ArrayList clone() const {
ArrayList array;
if (_vertexes.valid())
array._vertexes = dynamic_cast<osg::Array*>(_vertexes->cloneType());
if (_normals.valid())
array._normals = dynamic_cast<osg::Array*>(_normals->cloneType());
if (_colors.valid())
array._colors = dynamic_cast<osg::Array*>(_colors->cloneType());
if (_secondaryColors.valid())
array._secondaryColors = dynamic_cast<osg::Array*>(_secondaryColors->cloneType());
if (_fogCoords.valid())
array._fogCoords = dynamic_cast<osg::Array*>(_fogCoords->cloneType());
array._texCoordArrays.resize(_texCoordArrays.size());
for (unsigned int i = 0; i < _texCoordArrays.size(); i++) {
if (_texCoordArrays[i].valid())
array._texCoordArrays[i] = dynamic_cast<osg::Array*>(_texCoordArrays[i]->cloneType());
}
return array;
}
void setToGeometry(osg::Geometry& geom) {
if (_vertexes.valid())
geom.setVertexArray(_vertexes.get());
if (_normals.valid()) {
geom.setNormalArray(_normals.get());
geom.setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
}
if (_colors.valid()) {
geom.setColorArray(_colors.get());
geom.setColorBinding(osg::Geometry::BIND_PER_VERTEX);
}
if (_secondaryColors.valid()) {
geom.setSecondaryColorArray(_secondaryColors.get());
geom.setSecondaryColorBinding(osg::Geometry::BIND_PER_VERTEX);
}
if (_fogCoords.valid()) {
geom.setFogCoordArray(_fogCoords.get());
geom.setFogCoordBinding(osg::Geometry::BIND_PER_VERTEX);
}
for (unsigned int i = 0; i < _texCoordArrays.size(); ++i) {
if (_texCoordArrays[i].valid())
geom.setTexCoordArray(i, _texCoordArrays[i].get());
}
}
};
struct GeometrySplitter
{
GeometrySplitter(osg::Geometry& geometry ) : _geometry(geometry) {
_arraySrc = ArrayList(geometry);
}
void split(unsigned int maxElements)
{
osg::Geometry::PrimitiveSetList primitives = _geometry.getPrimitiveSetList();
for (unsigned int i = 0; i < primitives.size(); i++) {
osg::DrawElements* currentPrimitives = dynamic_cast<osg::DrawElements*>(primitives[i].get());
unsigned int currentPrimitiveIndex = 0;
while (currentPrimitiveIndex < currentPrimitives->getNumIndices()) {
unsigned int nbElements = currentPrimitives->getNumIndices() - currentPrimitiveIndex;
if (nbElements > maxElements) {
nbElements = maxElements;
}
ArrayList arrayDst = _arraySrc.clone();
osg::DrawElementsUShort* primitives = new osg::DrawElementsUShort(currentPrimitives->getMode());
std::map<unsigned int,unsigned int> global2local;
for (unsigned int index = 0; index < nbElements; index++) {
unsigned int idx = currentPrimitives->index(currentPrimitiveIndex+index);
unsigned int localidx;
if (global2local.find(idx) == global2local.end()) {
unsigned int newindex = _arraySrc.append(idx, arrayDst);
global2local[idx] = newindex;
}
localidx = global2local[idx];
primitives->push_back(localidx);
}
currentPrimitiveIndex += nbElements;
osg::Geometry* geom = new osg::Geometry;
geom->getPrimitiveSetList().push_back(primitives);
geom->setStateSet(_geometry.getStateSet());
arrayDst.setToGeometry(*geom);
_geometryList.push_back(geom);
}
}
}
ArrayList _arraySrc;
osg::Geometry& _geometry;
GeometryList _geometryList;
};
struct TriangleConvertorVertexes
{
osg::ref_ptr<osg::Vec3Array> _vertexes;
void operator()(const osg::Vec3& v1,const osg::Vec3& v2,const osg::Vec3& v3, bool treatVertexDataAsTemporary) {
_vertexes->push_back(v1);
_vertexes->push_back(v2);
_vertexes->push_back(v3);
}
};
struct SetupTriangleConvertorVertexes : public osg::TriangleFunctor<TriangleConvertorVertexes>
{
SetupTriangleConvertorVertexes() {
_vertexes = new osg::Vec3Array;
}
};
class SplitGeometryVisitor : public osg::NodeVisitor
{
public:
SplitGeometryVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {
_maxVertexes = 65535;
_maxPrimitivesIndexes = 65535;
}
void convertToBindPerVertex(osg::Geometry& srcGeom) {
unsigned int size = srcGeom.getVertexArray()->getNumElements();
if (srcGeom.getNormalArray() && srcGeom.getNormalBinding() != osg::Geometry::BIND_PER_VERTEX) {
ConvertToBindPerVertex()(srcGeom.getNormalArray(), srcGeom.getNormalBinding(), srcGeom.getPrimitiveSetList(), size);
srcGeom.setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
}
if (srcGeom.getColorArray() && srcGeom.getColorBinding() != osg::Geometry::BIND_PER_VERTEX) {
ConvertToBindPerVertex()(srcGeom.getColorArray(), srcGeom.getColorBinding(), srcGeom.getPrimitiveSetList(), size);
srcGeom.setColorBinding(osg::Geometry::BIND_PER_VERTEX);
}
if (srcGeom.getSecondaryColorArray() && srcGeom.getSecondaryColorBinding() != osg::Geometry::BIND_PER_VERTEX) {
ConvertToBindPerVertex()(srcGeom.getSecondaryColorArray(), srcGeom.getSecondaryColorBinding(), srcGeom.getPrimitiveSetList(), size);
srcGeom.setSecondaryColorBinding(osg::Geometry::BIND_PER_VERTEX);
}
if (srcGeom.getFogCoordArray() && srcGeom.getFogCoordBinding() != osg::Geometry::BIND_PER_VERTEX) {
ConvertToBindPerVertex()(srcGeom.getFogCoordArray(), srcGeom.getFogCoordBinding(), srcGeom.getPrimitiveSetList(), size);
srcGeom.setFogCoordBinding(osg::Geometry::BIND_PER_VERTEX);
}
}
unsigned int splitByVertexArray(osg::Geometry& srcGeom, GeometryList& list)
{
convertToBindPerVertex(srcGeom);
osgUtil::IndexMeshVisitor opt;
opt.makeMesh(srcGeom);
GeometrySplitter splitter(srcGeom);
splitter.split(_maxVertexes);
for (unsigned int i = 0; i < splitter._geometryList.size(); i++) {
list.push_back(splitter._geometryList[i].get());
}
return splitter._geometryList.size();
}
void apply(osg::Geode& node) {
GeometryList listGeometry;
bool touched = false;
for (unsigned int i = 0; i < node.getNumDrawables(); ++i) {
osg::Geometry* geom = dynamic_cast<osg::Geometry*>(node.getDrawable(i));
bool processed = false;
if (geom) {
osg::Array* array = geom->getVertexArray();
if (array->getNumElements() > _maxVertexes) {
int nb = splitByVertexArray(*geom, listGeometry);
osg::notify(osg::NOTICE) << "geometry " << geom << " " << geom->getName() << " splitted to " << nb << " models because vertexes size " << array->getNumElements() << " is more than " << _maxVertexes << std::endl;
processed = true;
touched = true;
}
}
if (!processed) {
listGeometry.push_back(geom);
}
}
if (touched) {
node.removeDrawables(0,node.getNumDrawables());
for (unsigned int d = 0; d < listGeometry.size(); d++) {
node.addDrawable(listGeometry[d].get());
}
}
}
unsigned int _maxVertexes;
unsigned int _maxPrimitivesIndexes;
};
class ReaderWriterSplit : public osgDB::ReaderWriter
{
public:
ReaderWriterSplit()
{
supportsExtension("split","Split geometry if more than 65535 vertexes, Psuedo loader.");
}
virtual const char* className() const { return "ReaderWriterSplit"; }
virtual ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
{
std::string ext = osgDB::getLowerCaseFileExtension(fileName);
if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
// strip the pseudo-loader extension
std::string subLocation = osgDB::getNameLessExtension( fileName );
if ( subLocation.empty() )
return ReadResult::FILE_NOT_HANDLED;
// recursively load the subfile.
osg::ref_ptr<osg::Node> node = osgDB::readNodeFile( subLocation, options );
if( !node.valid() )
{
// propagate the read failure upwards
osg::notify(osg::WARN) << "Subfile \"" << subLocation << "\" could not be loaded" << std::endl;
return ReadResult::FILE_NOT_HANDLED;
}
SplitGeometryVisitor visitor;
node->accept(visitor);
return node.release();
}
};
// Add ourself to the Registry to instantiate the reader/writer.
REGISTER_OSGPLUGIN(split, ReaderWriterSplit)
SET(TARGET_SRC ReaderWriterSplit.cpp ) #### end var setup ### SETUP_PLUGIN(split)
signature.asc
Description: This is a digitally signed message part
_______________________________________________ osg-submissions mailing list [email protected] http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
