How can I "pick" a single bone (or nose)?

I would like to the user to be able to “pick” a part of a character’s body.

If I run the HelloPicking tutorial described here:



https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:beginner:hello_picking



…and I pick a spot on Oto’s body, then I get a message like:



Collision #0 hit Oto-geom-1 at (-0.5523785, -3.4915211, -0.2742815), 10.86539 wu away.



…which is a good start. But that Oto-geom-1 represents all of Oto’s body as a single spatial.



Is there a straighforward way to find out which of Oto’s bones is closest to the collision point?

[java]

SkeletonControl skeletonControl = node.getChild(0).getControl(SkeletonControl.class); //depends on the node where attached skeleton

//or

SkeletonControl skeletonControl = node.getControl(SkeletonControl.class);

Bone bone = skeletonControl.getSkeleton().getBone("YOUR_BONE");



[/java]



And to the bone you can attach(set the same transform) a box geometry for picking.

The answer is in your question:

@stub22 said:
But that Oto-geom-1 represents all of Oto's body as a single spatial.

Thank you @mifth. Assuming that the model may be animating when I try to pick it

(so I cannot use the bone’s “bind pose” transforms), it seems that to determine the

world bounding-cylinder for a bone, I will need to:


  1. Get the model-space transforms for the bone.
  2. Append those transforms to the world transform of the model’s root spatial.



    … which should give me the transforms of the cylinder. Then I must somehow

    determine the “length” and “radius” of the bone’s bounding cylinder. For an

    accurate radius, I would need to dive into the meshes and do something

    similar to what is going on in com.jme3.bullet.control.ragdoll.RagdollUtils.

    But to just get the length (assuming I can live with a fake radius value), it

    seems I could do something like:



    For a given “current” bone, look at all its child bones, and take the position

    of the farthest child as being the “end” of the current bone.



    Am I on the right track?

@stub22:

OK, in case you really want to pick a single bone which “in the way” of your current mouse ray, you have to attach to your bone a Geometry!!!



The current collision checking only return the spatial (exactly a Geometry), and even you modify or make your own code of checking, it’s really the only way : “We must have something visible and has volume to check collision to”



More about the code: com.jme3.bullet.control.ragdoll.RagdollUtils is exactly where you should take a good look, everything is there!!! :stuck_out_tongue:



P.s: If you want to make your bone picking more efficient , you should only include your bone wrapper’s geometry in your checking process!

Thank you @atomix for emphasizing that having a Geometry to go with the Bone is the way to go (to use exisiting com.jme3.collisions

framework for the detailed-hit-detect), and for confirming that com.jme3.bullet.control.ragdoll.RagdollUtils is the right starting

point for making those geometries. It looks like I can copy scanSpatial() and boneRecursion() from KinematicRagdollControl,

and then just chop off the physics part, to get just the HullCollisionShapes.



Those HullCollisionShapes are for physics collisions only, and not directly usable with the com.jme3.collision package - right?

But from there, I could use com.jme3.bullet.util.DebugShapeFactory.getDebugShape() to turn the CollisionShapes into

meshes, which I can combine with a transparent material (or visible, for debugging) to produce geometries eligible for

com.jme3.collision tests.



Then, only when it is time to check-model-hit-details (or when we are in some super-debug mode), we can

copy the world-transforms of the bones over to these transparent geometries, and do an extra mouse-ray hit-test against

these spatials only.



Not a horrible solution, but I am still open to hearing of an easier way, or any corrections to the plan I just described.

Thanks again to all three of y’all for your helpful suggestions!

Here’s my thoughts, I’ve never tryed this so someone may need to step in and correct me…


  1. Cast your Ray (against the original geometry);
  2. detrmine the correct CollisionResult;
  3. use CollisionResult.getTriangleIndex() to get the selected ‘face’;
  4. using the vertices of that face:

    a) check the BoneIndex buffer to figure out which bones the vertex is influcenced by; or

    b) combine with values from the BoneWeight buffer to determine the single most infulential bone on the entire face.
2 Likes
@stub22 said:
...
and for confirming that com.jme3.bullet.control.ragdoll.RagdollUtils is the right starting
point for making those geometries. It looks like I can copy scanSpatial() and boneRecursion() from KinematicRagdollControl,
and then just chop off the physics part, to get just the HullCollisionShapes.

Those HullCollisionShapes are for physics collisions only, and not directly usable with the com.jme3.collision package - right?
But from there, I could use com.jme3.bullet.util.DebugShapeFactory.getDebugShape() to turn the CollisionShapes into
meshes, which I can combine with a transparent material (or visible, for debugging) to produce geometries eligible for
com.jme3.collision tests.

...


It sounds complicated ! But in this not-ideal world, we have to walk in the hard way, :p . And YES, you plan the right way to go... I don't remember exactly but @nehon make a RagDoll test with mouse ray collision check (or not?) , I will take a better look when I back home. It's in the JMETest (you should look there too)!

@thetoucher : Excelent idea, :stuck_out_tongue: , you’re smart!



Anyway, IMO, its result can be a little bit different from @stub22 approach, so it can be the Second way to select a bone:


  1. Select with World Position by BoneDebugShape collision check


  2. Select by MeshTriangle for and sort the most inluenced bone!



    @thetoucher : Again, you’re smart!