best way to determine which mesh buffer has been clicked?

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
openglman
Posts: 15
Joined: Wed Jan 05, 2011 11:34 pm

best way to determine which mesh buffer has been clicked?

Post 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
openglman
Posts: 15
Joined: Wed Jan 05, 2011 11:34 pm

Post 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();
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post 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.
openglman
Posts: 15
Joined: Wed Jan 05, 2011 11:34 pm

Post 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
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post 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.
openglman
Posts: 15
Joined: Wed Jan 05, 2011 11:34 pm

Post 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
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Try the transformed bounding box.
openglman
Posts: 15
Joined: Wed Jan 05, 2011 11:34 pm

Post by openglman »

hmm it seems IMeshBuffer doesn't have the method getTransformedBoundingBox, only ISceneNode appears to have it?
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Ah yeah, sure. Call getTransformation on the scene node and use matrix.transform(bbox)
openglman
Posts: 15
Joined: Wed Jan 05, 2011 11:34 pm

Post by openglman »

ah you are my savior!! thank you that works like a charm! wooooot :)
openglman
Posts: 15
Joined: Wed Jan 05, 2011 11:34 pm

Post 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!
Post Reply