Version 2 (modified by martin, 7 years ago)

--

Analysing A Scenegraph

Once a scenegraph is loaded you may wish to analyse the in memory tree of nodes. Ideally you would use a nodevisitor, but here is a simple piece of C code that works:

= void analyseGeode(osg::Geode *geode);

void analysePrimSet(osg::PrimitiveSet*prset, const osg::Vec3Array *verts);

void analyse(osg::Node *nd) {
	/// here you have found a group.
    osg::Geode *geode = dynamic_cast<osg::Geode *> (nd);
	if (geode) { // analyse the geode. If it isnt a geode the dynamic cast gives NULL.
		analyseGeode(geode);
	} else {
		osg::Group *gp = dynamic_cast<osg::Group *> (nd);
		if (gp) {
			osg::notify(osg::WARN) << "Group "<<  gp->getName() <<std::endl;
			for (unsigned int ic=0; ic<gp->getNumChildren(); ic++) {
				analyse(gp->getChild(ic));
			}
		} else {
			osg::notify(osg::WARN) << "Unknown node "<<  nd <<std::endl;
		}
	}
}
// divide the geode into its drawables and primitivesets:

void analyseGeode(osg::Geode *geode) {
    for (unsigned int i=0; i<geode->getNumDrawables(); i++) {
		osg::Drawable *drawable=geode->getDrawable(i);
		osg::Geometry *geom=dynamic_cast<osg::Geometry *> (drawable);
		for (unsigned int ipr=0; ipr<geom->getNumPrimitiveSets(); ipr++) {
			osg::PrimitiveSet* prset=geom->getPrimitiveSet(ipr);
			osg::notify(osg::WARN) << "Primitive Set "<< ipr << std::endl;
			analysePrimSet(prset, dynamic_cast<const osg::Vec3Array*>(geom->getVertexArray()));
		}
    }
}

void analysePrimSet(osg::PrimitiveSet*prset, const osg::Vec3Array *verts) {
	unsigned int ic;
	unsigned int i2;
	unsigned int nprim=0;
	osg::notify(osg::WARN) << "Prim set type "<< prset->getMode() << std::endl;
	for (ic=0; ic<prset->getNumIndices(); ic++) { // NB the vertices are held in the drawable -
		osg::notify(osg::WARN) << "vertex "<< ic << " is index "<<prset->index(ic) << " at " <<
			(* verts)[prset->index(ic)].x() << "," <<
			(* verts)[prset->index(ic)].y() << "," << 
			(* verts)[prset->index(ic)].z() << std::endl;
    }
	// you might want to handle each type of primset differently: such as:
	switch (prset->getMode()) {
	case osg::PrimitiveSet::TRIANGLES: // get vertices of triangle
		osg::notify(osg::WARN) << "Triangles "<< nprim << " is index "<<prset->index(ic) << std::endl;
		for (i2=0; i2<prset->getNumIndices()-2; i2+=3) {
		}
	break;
	case osg::PrimitiveSet::TRIANGLE_STRIP: // look up how tristrips are coded
	break;
	// etc for all the primitive types you expect. EG quads, quadstrips lines line loops....
	}
}=

This code can be inserted into (say) osgviewer.cpp, and called thus:

analyse(loadedModel.get());