Creating bounding box for every node in the scene

1,937 views
Skip to first unread message

nerazzurri_4

unread,
Aug 20, 2011, 5:49:49 PM8/20/11
to osgworks-users
Hi,

I have tried the osgwbvv application and it is extremely useful to get
the size of a particular object. I am trying to incorporate its
functionality to create and display the bounding box of any node the
user selects in the scene.

I pass the node whose bounding box is required to the function below:

void OsgViewerWindow::drawBoundingBox(osg::ref_ptr<osg::Node> &node)
{
//initialize the visitor, matrixtransform and geode
osg::ref_ptr<osg::ComputeBoundsVisitor> cbv = new
osg::ComputeBoundsVisitor();
osg::ref_ptr<osg::MatrixTransform> boundingBoxMt = new
osg::MatrixTransform();
osg::ref_ptr<osg::Geode> boundingBoxGeode = new osg::Geode();
osg::BoundingBox geodeBoundingBox;
//attach the compute bounds visitor to the node
node->accept( *cbv );

osg::BoundingBox bb( cbv->getBoundingBox() );
//set the matrix for the transform
boundingBoxMt-
>setMatrix( osg::Matrix::translate( geodeBoundingBox.center() ) );
//get the extents of the bounding box, call osgWorks function to
draw
osg::Vec3 ext( bb._max - bb._min );
boundingBoxGeode->addDrawable( osgwTools::makeWireBox( ext *
0.5 ) );
//add geode under Mt
boundingBoxMt->addChild(boundingBoxGeode);
//add Mt to subgraph
osgSingleViewerWidget->root->addChild(boundingBoxMt);

QMessageBox* msgBox = new QMessageBox;
//msgBox.setModal(false);
msgBox->setText("The dimensions of the node object are:\n"
"X-Axis: " + QString::number(ext.x()) + "\n"
"Y-Axis: " + QString::number(ext.y()) + "\n"
"Z-Axis: " + QString::number(ext.z()) );
msgBox->show();
//msgBox.exec();
boundingBoxMt->removeChildren(0, boundingBoxMt->getNumChildren());
}

However when I try this, I get a bounding box for not just this node
but also for those nodes lying below it in the scenegraph. I think I
may need to attach the visitor to root and then get the node path upto
the selected node. But I was not sure how I can get the bounding box
with that approach. I must also mention that the scene graph involves
rotation transforms too, as some threads mention that this makes a
difference for bounding box computation.

I was hoping to get some advice on how I can create the bounding box
for a particular node in the scene graph.

Thanks.

Paul Martz

unread,
Aug 22, 2011, 9:02:04 PM8/22/11
to osgwork...@googlegroups.com

Hi Sanat -- I don't see where you are getting the parent transformation matrix
from. You need a NodePath leading up to the node parameter, and then you can
getLocalToWorld() from that NodePath.

There are also a couple other things you should know about that might help:

osgWorks provides functions to directly transform OSG bounding volumes. See the
<osgwTools/Transform.h> header.

Also, svn trunk of osgWorks (warning: under heavy development pushing towards a
2.0 release) now contains versions of the makeBox(), makeWireBox(),
makeAltAzSphere(), etc, functions that take an osg::Matrix as the first
parameter, and return a Geometry that is already transformed by that matrix.

I hope this info helps.

--
-Paul Martz Skew Matrix Software
http://www.skew-matrix.com/

Sanat Talmaki

unread,
Aug 23, 2011, 7:59:23 AM8/23/11
to osgwork...@googlegroups.com
Hi Paul,

Sorry to bother you again.

I followed your earlier mail's suggestion and some threads in the osg forum and used the nodePath in the function that creates the bounding sphere geometry. I want to create both spheres and boxes based on certain user selection parameters, so the function below creates sphere geometry as in osgwbvv:

I have attached a couple of screenshots:
1) Placing the sphere geode under a matrix transform and applying the world matrix from getLocalToWorldCoord(..) to this matrixTransform. Then place this MatrixTransform under root node.
2) Placing the Matrix transform from above under the parent node of the object whose sphere is created. (as expected, this shows results as if transforms were applied twice over - once from the parent node and once from the world coordinates matrix).

The code for the function is below:

void OsgViewerWindow::drawBoundingSphere(osg::NodePath &nodePath)
{
  //use node path to get world matrix
  osg::Matrix worldMatrix = osg::computeLocalToWorld(nodePath);
  //init matrix transform

  osg::ref_ptr<osg::MatrixTransform> boundingBoxMt = new osg::MatrixTransform();
  boundingBoxMt->postMult(worldMatrix);
  //init geode

  osg::ref_ptr<osg::Geode> boundingBoxGeode = new osg::Geode();

  //apply state set for bb geode
  osg::StateSet* ss = boundingBoxGeode->getOrCreateStateSet();
  ss->setAttributeAndModes( new osg::PolygonMode(  osg::PolygonMode::FRONT_AND_BACK,  osg::PolygonMode::LINE ) );
  ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); 

  //last node in the node path corresponds to the current node the visitor is at
  const osg::BoundingSphere bs( nodePath.back()->getBound() );
  boundingBoxGeode->addDrawable( osgwTools::makeGeodesicSphere( bs._radius, 1 ) );    
  //add geode under Mt
  boundingBoxMt->addChild(boundingBoxGeode);

  //add Mt to subgraph
  //add to the root (if world matrix is right, this should place it correctly?)
  osgSingleViewerWidget->root->addChild(boundingBoxMt); 
  //place the bounding box under the Matrixtransform for the 'current' node
  nodePath.back()->getParent(0)->asTransform()->addChild(boundingBoxMt);
 
  return;
}

Thanks,
Sanat.






--
You received this message because you are subscribed to the Google Groups "osgworks-users" group.
To post to this group, send email to osgworks-users@googlegroups.com.
To unsubscribe from this group, send email to osgworks-users+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/osgworks-users?hl=en.


place_under_parent-transform.jpg
place_under_root-node.jpg

Paul Martz

unread,
Aug 23, 2011, 8:57:41 AM8/23/11
to osgwork...@googlegroups.com
On 8/23/2011 5:59 AM, Sanat Talmaki wrote:
> Hi Paul,
>
> Sorry to bother you again.
>
> I followed your earlier mail's suggestion and some threads in the osg forum
> and used the nodePath in the function that creates the bounding sphere
> geometry. I want to create both spheres and boxes based on certain user
> selection parameters, so the function below creates sphere geometry as in osgwbvv:
>
> I have attached a couple of screenshots:
> 1) Placing the sphere geode under a matrix transform and applying the world
> matrix from getLocalToWorldCoord(..) to this matrixTransform. Then place this
> MatrixTransform under root node.

That would work, except from your code below, if the last Node in the NodePath
is a Transform node, then you need to make a copy of the NodePath and pop the
Transform off the back. Otherwise that Transform would be applied twice, once in
the matrix derived from the NodePath and once in the geometry of the BoundingBox.

> 2) Placing the Matrix transform from above under the parent node of the object
> whose sphere is created. (as expected, this shows results as if transforms
> were applied twice over - once from the parent node and once from the world
> coordinates matrix).

That won't work, but osgWorks has AbsoluteModelTransform. If you use that
instead of MatrixTransform, it should work. Of course you still need to handle
the case where the last Node in your NodePath is a Transform (as I mentioned
previously).
-Paul

Sanat Talmaki

unread,
Aug 23, 2011, 9:08:37 AM8/23/11
to osgwork...@googlegroups.com
That would work, except from your code below, if the last Node in the NodePath is a Transform node, then you need to make a copy of the NodePath and pop the Transform off the back. Otherwise that Transform would be applied twice, once in the matrix derived from the NodePath and once in the geometry of the BoundingBox.

I too expected it to work. But as seen in the screenshot place_under_root-node.jpg, it is not giving the right displacement & rotation.
I am ensuring that the node returned (i.e. at the end of the node path) is the object and not a transform.

Is it normal for there to be an offset ? I expected it to completely bound the object after placing the sphere under its world matrix.

Thanks,
Sanat.




 

place_under_root-node.jpg

Paul Martz

unread,
Aug 23, 2011, 9:25:29 AM8/23/11
to osgwork...@googlegroups.com
On 8/23/2011 7:08 AM, Sanat Talmaki wrote:
That would work, except from your code below, if the last Node in the NodePath is a Transform node, then you need to make a copy of the NodePath and pop the Transform off the back. Otherwise that Transform would be applied twice, once in the matrix derived from the NodePath and once in the geometry of the BoundingBox.

I too expected it to work. But as seen in the screenshot place_under_root-node.jpg, it is not giving the right displacement & rotation.
I am ensuring that the node returned (i.e. at the end of the node path) is the object and not a transform.

Apparently there is some kind of bug in your code, but if the last Node in the NodePath isn't a Transform, then I don't know what it could be. It definitely seems like a Transform problem so it should be pretty easy to track down with small simple test cases.


Is it normal for there to be an offset ? I expected it to completely bound the object after placing the sphere under its world matrix.

The bounding volume completely surrounds its Node and the subgraph rooted at that Node. There is no offset.
   -Paul


Paul Martz

unread,
Aug 23, 2011, 9:36:15 AM8/23/11
to osgwork...@googlegroups.com
I think I see the problem. The dumptruck model isn't centered on the origin, but
the osgWorks geodesic sphere is centered on the origin. You need to transform
the sphere geometry by the center of the BoundingSphere.

Use the new makeGeodesicSphere() that takes a Matrix as the first parameter.
-Paul

Sanat Talmaki

unread,
Aug 23, 2011, 12:12:07 PM8/23/11
to osgwork...@googlegroups.com
Hi Paul,

Yup, you are spot on! That was the problem. I used the getWorldFromLocalCoords but didn't realize I had to translate the sphere by its center.

Thanks for the help.

Sincerely,
Sanat.




  -Paul

Reply all
Reply to author
Forward
0 new messages