Page 1 of 1

best way to determine which mesh buffer has been clicked?

Posted: Sat Jan 08, 2011 4:57 pm
by openglman
Hi,

I have some code written that will give me the ISceneNode object that has been clicked and it works great. However, I plan to have all my models in one ms3d file where I use meshbuffers to deal each individual object inside my scene.

Is the best way to do this to draw an invisible box around each meshbuffer and then add it to the scene so that I know what has been clicked?

Thanks

Posted: Sat Jan 08, 2011 9:11 pm
by openglman
I have something that appears to work. For each meshbuffer/joint within my scene node I create a SphereSceneNode based on the position and size of the meshbuffers bounding box and set the material to vertexalpha and then make it invisible. Then I create a triangle selector for it so that I can use getSceneNodeAndCollisionPointFromRay to determine if I have a collision from the ray cast from my camera. This way I can determine which object in my model scene has been selected.

This seems to work pretty good, I am just wondering if this is the best way or if there are any other ways to this better?

Code: Select all

mynode->getMesh()->getMeshBuffer(materialindex)->getBoundingBox();
sphere = smgr->addSphereSceneNode(1.0, 16, mynode, 999, box.getCenter(), core::vector3df(0,0,0), box.getExtent()/1.5); 

sphere->setMaterialType(EMT_TRANSPARENT_VERTEX_ALPHA);
smgr->getMeshManipulator()->setVertexColorAlpha(sphere->getMesh(), 0);

scene::ITriangleSelector* selector = 0;
selector = smgr->createTriangleSelector(sphere->getMesh(), sphere);
sphere->setTriangleSelector(selector);
selector->drop();

Posted: Sat Jan 08, 2011 9:23 pm
by hybrid
No, that's definitely not a good idea. Better use a dummy scene node which has no geometry to render at all. You'd be even better off with a cube node. But every node with geometry will send the geometry to the gpu, whether it is transparent or not. You can disable the color mask and depth buffer in order to avoid any rendering (should be faster than the alpha test) but it's still overhead.

Posted: Sat Jan 08, 2011 9:57 pm
by openglman
If I use a dummy scene node instead of a sphere or cube, will I still be able to use the triangle selector for collision detection? If the scene node doesn't have any geometry then it won't have a mesh right? Don't I need a mesh in order to use the triangle selector method?

Thanks

Posted: Sat Jan 08, 2011 10:27 pm
by hybrid
Why not just use a bbox test, as it's much faster and the geometry of the sphere is far from the actual geometry from the scene node.

Posted: Sat Jan 08, 2011 11:38 pm
by openglman
hybrid wrote:Why not just use a bbox test, as it's much faster and the geometry of the sphere is far from the actual geometry from the scene node.
Initially that is what I tried to do. I load my model and then I scale it so that it is the size that I want.

When I call mynode->setDebugDataVisible(scene::EDS_BBOX_ALL); all of the bounding boxes look perfect.

So I called getBoundingBox on my mesh buffer (as shown below) it does return a box of the correct size because I called draw3DBox later and it showed up properly. However when I called intersectsWithLine on my bbox it never returns true. I can never get it to return true.

Code: Select all

aabbox3df box = mynode->getMesh()->getMeshBuffer(2)->getBoundingBox();

...
core::line3d<f32> ray;
ray.start = cam->getPosition();
ray.end = ray.start + (cam->getTarget() - ray.start).normalize() * 30000.0f;

if(box.intersectsWithLine(ray))
{
    //never gets here using the bounding box!

}
It would be nice if I could just do a simple test using the bounding box and a call to intersectsWithLine. Do you know what I might be doing wrong here?

Thanks

Posted: Sat Jan 08, 2011 11:51 pm
by hybrid
Try the transformed bounding box.

Posted: Sun Jan 09, 2011 12:02 am
by openglman
hmm it seems IMeshBuffer doesn't have the method getTransformedBoundingBox, only ISceneNode appears to have it?

Posted: Sun Jan 09, 2011 12:35 am
by hybrid
Ah yeah, sure. Call getTransformation on the scene node and use matrix.transform(bbox)

Posted: Sun Jan 09, 2011 2:10 am
by openglman
ah you are my savior!! thank you that works like a charm! wooooot :)

Posted: Sun Jan 09, 2011 6:41 pm
by openglman
Just in case anyone else needs the code. Here is what I did to test for a collision between a ray cast from the camera and a meshbuffer bounding box.

Code: Select all

IAnimatedMesh* mesh = smgr->getMesh("../../media/test3.x");
IAnimatedMeshSceneNode* mynode = smgr->addAnimatedMeshSceneNode( mesh, 0);
aabbox3df box = mynode->getMesh()->getMeshBuffer(2)->getBoundingBox();

...

core::line3d<f32> ray;
ray.start = cam->getPosition();
ray.end = ray.start + (cam->getTarget() - ray.start).normalize() * 30000.0f;
matrix4 matrix;
mynode->getAbsoluteTransformation().getInverse(matrix);
	
matrix.transformVect(ray.start);
matrix.transformVect(ray.end);

if(box.intersectsWithLine(ray))
{
   //we have a collision
}
Cheers all!