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

Reply via email to