Hi, I've been playing around with the "Computing the world bounding box of any node" example in the Cookbook, which uses a ShapeDrawable. I've read in the Doxygen docs that:
> > The implementation of ShapeDrawable is not geared to efficiency; it's better > to think of it as a convenience to render Shapes easily (perhaps for test or > debugging purposes) than as the right way to render basic shapes in some > efficiency-critical section of code. > So, I thought I would try to create a custom box shape using a Geometry: osgshapes.h Code: #ifndef OSGSHAPES_H #define OSGSHAPES_H #include "osg/PositionAttitudeTransform" namespace osg { class Geode; } class Shape: public osg::PositionAttitudeTransform { public: Shape( const bool w = true ); virtual bool create() = 0; int getScaleFactor() const { return scaleFactor; } void setScaleFactor( const int s ); bool isWireframe() const { return wire; } void setWireframe( const bool w ); protected: virtual ~Shape(); private: bool wire; int scaleFactor; }; class Box: public Shape { public: Box( const double l = 1. ); bool create(); double getLenght() const { return length; } void setLenght( const double l ); protected: ~Box(); private: double length; }; #endif osgshapes.cpp Code: namespace { namespace BoxFactory { void drawBox( osg::ref_ptr<osg::Vec3Array> vert ) { vert->push_back( osg::Vec3d( -1.0, -1.0, 1.0 ) ); vert->push_back( osg::Vec3d( 1.0, -1.0, 1.0 ) ); vert->push_back( osg::Vec3d( 1.0, 1.0, 1.0 ) ); vert->push_back( osg::Vec3d( -1.0, 1.0, 1.0 ) ); vert->push_back( osg::Vec3d( -1.0, -1.0, -1.0 ) ); vert->push_back( osg::Vec3d( 1.0, -1.0, -1.0 ) ); vert->push_back( osg::Vec3d( 1.0, 1.0, -1.0 ) ); vert->push_back( osg::Vec3d( -1.0, 1.0, -1.0 ) ); } osg::ref_ptr<osg::DrawElementsUInt> getQuads() { osg::ref_ptr<osg::DrawElementsUInt> quads = new osg::DrawElementsUInt( GL_QUADS ) ; // FRONT quads->push_back( 0 ); quads->push_back( 1 ); quads->push_back( 2 ); quads->push_back( 3 ); // BOTTOM quads->push_back( 0 ); quads->push_back( 1 ); quads->push_back( 5 ); quads->push_back( 4 ); // LEFT quads->push_back( 0 ); quads->push_back( 4 ); quads->push_back( 7 ); quads->push_back( 3 ); // BACK quads->push_back( 4 ); quads->push_back( 5 ); quads->push_back( 6 ); quads->push_back( 7 ); // TOP quads->push_back( 3 ); quads->push_back( 2 ); quads->push_back( 6 ); quads->push_back( 7 ); // RIGHT quads->push_back( 1 ); quads->push_back( 5 ); quads->push_back( 6 ); quads->push_back( 2 ); return quads; } osg::ref_ptr<osg::Geode> buildBox() { osg::ref_ptr<osg::Geode> geode = new osg::Geode; osg::ref_ptr<osg::Geometry> geom = new osg::Geometry; geode->addDrawable( geom.get() ); osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; geom->setVertexArray( vertices ); // geom->setDataVariance( osg::Object::DYNAMIC ); // geom->setUseDisplayList( false ); // geom->setUseVertexBufferObjects( true ); drawBox( vertices ); osg::ref_ptr<osg::DrawElementsUInt> quads = getQuads(); geom->addPrimitiveSet( quads ); geom->getOrCreateStateSet()->setAttributeAndModes( new osg::Point( 5.0f ) ); geom->addPrimitiveSet( new osg::DrawArrays(GL_POINTS, 0, vertices->size() ) ); return geode; } } // End BoxFactory } Shape::Shape( const bool w ) : osg::PositionAttitudeTransform(), scaleFactor( 1.0 ) { setWireframe( w ); } Shape::~Shape() { } void Shape::setScaleFactor( const int s ) { if( s == scaleFactor ) { return; } scaleFactor = s; const osg::Vec3d scale = getScale() * s; setScale( scale ); } void Shape::setWireframe( const bool w ) { if( w == wire ) { return; } wire = w; osg::observer_ptr<osg::StateSet> ss = getOrCreateStateSet(); ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); osg::PolygonMode::Mode mode = ( w ) ? osg::PolygonMode::LINE : osg::PolygonMode::FILL ; osg::PolygonMode* pmode = new osg::PolygonMode( osg::PolygonMode::FRONT_AND_BACK, mode ) ; ss->setAttributeAndModes( pmode, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON ) ; } Box::Box( const double l ) : Shape(), length( l ) { setName( "Box" ); setLenght( l ); } Box::~Box() { } bool Box::create() { bool toret( false ); osg::ref_ptr<osg::Geode> geode = BoxFactory::buildBox(); if( geode.valid() ) { toret = addChild( geode ); } return toret; } void Box::setLenght( const double l ) { if( l == length ) { return; } setScaleFactor( l ); } Then, in my app: Cookbook's code Code: // This is the callback from the Cookbook osg::ref_ptr<BoundingBoxCallback> bbcb = new BoundingBoxCallback; osg::ref_ptr<osg::PositionAttitudeTransform> bboxNode = new osg::PositionAttitudeTransform; osg::ref_ptr<osg::Geode> bboxGeode = new osg::Geode; osg::ShapeDrawable* sd = new osg::ShapeDrawable( new osg::Box ); sd->setColor( osg::Vec4d( 1.0, 0.0, 0.0, 1.0 ) ); bboxGeode->addDrawable( sd ); bboxNode->addChild( bboxGeode.release() ); bboxNode->addUpdateCallback( bbcb.get() ); bboxNode->getOrCreateStateSet()->setAttributeAndModes( new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE ) ); bboxNode->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); Using my custom shape Code: // This is the callback from the Cookbook osg::ref_ptr<BoundingBoxCallback> bbcb = new BoundingBoxCallback; osg::ref_ptr<Box> bboxNode = new Box; bboxNode->setWireframe( true ); bboxNode->create(); bboxNode->addUpdateCallback( bbcb.get() ); bboxNode->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); Callback (I added an "active" flag so the callback will be run only once. Otherwise, it's the same code as in the Cookbook): Code: void BoundingBoxCallback::operator()( osg::Node* node, osg::NodeVisitor* ) { if( !isActive() || !getCurrentNode().valid() ) { return; } osg::ComputeBoundsVisitor cbbv; getCurrentNode()->accept( cbbv ); const osg::BoundingBox localBB = cbbv.getBoundingBox(); if( !localBB.valid() ) { return; } const osg::Matrix localToWorld = osg::computeLocalToWorld( node->getParent( 0 )->getParentalNodePaths()[ 0 ] ); osg::BoundingBox bb; for( unsigned int i( 0 ); i < 8; ++i ) { bb.expandBy( localBB.corner( i ) * localToWorld ); } osg::PositionAttitudeTransform* trans = static_cast<osg::PositionAttitudeTransform*>( node ); trans->setScale( osg::Vec3d( bb.xMax() - bb.xMin(), bb.yMax() - bb.yMin(), bb.zMax() - bb.zMin() ) ); trans->setPosition( bb.center() ); std::cout << "BB: " << "\n"; std::cout << "\tX m/M: " << bb.xMin() << " / " << bb.xMax() << std::endl; std::cout << "\tY m/M: " << bb.yMin() << " / " << bb.yMax() << std::endl; std::cout << "\tZ m/M: " << bb.zMin() << " / " << bb.zMax() << std::endl; std::cout << "TRANS->POS: " << trans->getPosition() << std::endl; disable(); } You can check what the output is with each code in the attached pics. They're labelled as original for the original code in the Cookbook and myshape for the code using my custom shape. As you can see, when using my custom shape the bounding box doesn't get updated. Inside the callback, the computed bounding box is the same whenever I'm using the original code or my shape, so I'm a bit puzzled beacuse when displaying the box it doesn't fit the model as nice as the Cookbook's code. If I don't use the callback and modify the box by hand, for example by scaling it, it works. So, what did I do wrong for this not to work? NOTE: This is for educational purposes only. ... Cheers and thanks! Andrés ------------------ Read this topic online here: http://forum.openscenegraph.org/viewtopic.php?p=61558#61558 Attachments: http://forum.openscenegraph.org//files/myshape_138.png http://forum.openscenegraph.org//files/original_181.png _______________________________________________ osg-users mailing list osg-users@lists.openscenegraph.org http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org