Ray casting sometime not working

Hy Guys,
This link points to a sample 1 Class program loading a Box and a GLB model then in the update() function performs ray casting from the current mouse cursor position. When there is a result it is printed to the console.
The problem - the ray casting works fine against the Box but not at all with the GLB model.
I have tested it with various models. With some of them it works fine, with others - the same problem occurs.

Here is the ray casting code :

public void simpleUpdate(float tpf) {

        CollisionResults results = new CollisionResults();
        Vector2f click2d = this.getInputManager().getCursorPosition().clone();
        Vector3f click3d = this.getCamera().getWorldCoordinates(
                click2d, 0f).clone();

        Vector3f dir = this.getCamera().getWorldCoordinates(
                click2d, 1f).subtractLocal(click3d).normalizeLocal();
        Ray ray = new Ray(click3d, dir);
        this.getRootNode().collideWith(ray, results);

        if (results.size() > 0) {
            CollisionResult closest = results.getClosestCollision();
            if (closest != null) {
                System.out.println("ray collides with: "+closest);
            }
        }
    }

What do you think? Is there a reliable way for doing the ray casting so that it will work with all models?

Thanks a lot!

Is the glb model undergoing hardware skinning?

Don’t know. How do I check that?

If the model has a SkinningControl, it is affected by hardware skinning. You can check that with the sdk’s scene composer, or you can write some code that will check for you at runtime.

glbModel.depthFirstTraversal(s -> {
    for (int i = 0; i < s.getNumControls(); i++) {
        System.out.println(s.getControl(i));
    }
});

Yes. It has a skinning control

Maybe its just a coincidence and not related but I have tested a few GLTF models and they worked just fine so maybe just maybe its related to the model being GLB and not GLTF?

I can’t remember if ray collisions do a bounds check first or not, but if so then it could be worth checking if the model has a proper BoundingBox.

It looks like the code for your ray direction is correct, although it never hurts to double check that the collisions are correct by visualizing the ray, or placing a small box on the contact point to ensure it is indeed picking the point that you click on the working models.

If neither of those are the issue and you think its related to being glb then it could also be worth importing the glb to blender, then re-exporting as gltf.

1 Like

From jME’s perspective, glb is gltf, just with a slightly different I/O handling since everything is packed into one binary file: jME GLB Loader.

2 Likes

What is a proper bounding box? How can I programmatically create/fix the BoundingBox or should I fix that in Blender?

A bounding box must enclose all of the visible geometry for a model or anything that tests against the bounding box to decide whether or not a model is visible/collides with a ray/etc. won’t work properly because those tests won’t correctly test against any geometry that’s “sticking out of” the bounding box.

You can easily create a visible model of a bounding box to see if there’s a problem with it or not:

public static Geometry makeWireframe(AssetManager assetManager, BoundingBox bounds) {

        Material wireMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        wireMat.setColor("Color", ColorRGBA.White);
        wireMat.getAdditionalRenderState().setLineWidth(1f);
        wireMat.getAdditionalRenderState().setWireframe(true);
        wireMat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);

        WireBox wireBox = new WireBox(bounds.getXExtent(), bounds.getYExtent(), bounds.getZExtent());

        Geometry wireGeom = new Geometry("Highlight");
        wireGeom.setMaterial(wireMat);
        wireGeom.setMesh(wireBox);

        return wireGeom;
    }

The BoundingBox parameter is the spatial’s world bound - you would call this like:

makeWireframe(assetManager, (BoundingBox) spatial.getWorldBound())

and then you’d attach it to the scene at the spatial’s position.

4 Likes

Thanks! I will add that to the program and see what kind of bounding box we have with this model…

2 Likes

You should also be able to easily view the model’s bounds by opening it in the SDK.

Here’s an example of a model I downloaded a while back that had a broken bounding box that does not encapsulate the model correctly.

It’s been a long time but I recall this model was giving me issues ignoring collisions until I fixed it to instead do collisions with separate hitboxes that get attached to the animated attachmentNodes. But I think you could also just try to set a new bounding box on the spatial to fix it that way too, if that is the issue of course.

4 Likes

When there is a skinning control, the mesh you see on screen is some frame of animation and may not at all represent the raw mesh data. I’ve had models that were 90 meters tall and some that were 2 millimeters tall when loaded, but on screen looked fine because the animation frame/pose scaled things correct.

When hardware skinning is enabled then JME never sees the visualized positions of vertexes because they are calculated in the shader (the hardware).

In these cases, you can turn off hardware skinning (it is a parameter on the skin control) but then you will be doing the bone-skinning on the CPU instead of the GPU.

This is why it’s quite common to add simpler (invisible) hit shapes and attach them to the bones at various places.

4 Likes

I understand. So I think I’ll try to turn off the hardware skinning because in that case I’m going to use the ray casting only for the “edit” mode for picking and positioning an object in the scene. Thanks!

Edit:
I turned off the hardware skinning:

setHardwareSkinningPreferred(false);

But still the ray casting is not working for that model.
Maybe I chose the wrong path for picking an object in the scene. There are a few editor builders here. what is your way for picking an object?

Maud picks vertices by looping over the vertices in the (software-skinned) model, calculating the screen location of each vertex, and then selecting the one closest to the mouse location.

If you want to use JME’s raycasting, I think the trick is to reset both the bounding volume (using updateBound()) and the BIH tree (using clearCollisionData()) of each animated mesh.

1 Like

I add a Lemur cursor listener to it. Then I receive the events. No muss, no fuss.

Note: model bounds, etc. have to be correct already. That’s a model problem.

1 Like

I do my scene picking with a ray nearly identical to the code you’re using.

I also got a chance to download your test-app and I managed to get the collisions to work!

But only after removing the skinningControl and then scaling the model x100 to make it the correct size:

        this.player1 = loadPlayer(new Vector3f(0,-6,0));
        this.player2 = loadPlayer(new Vector3f(0,1,0));
        //ignoreJoints(this.player1, this.player2);
        //ignoreJoints(this.player2, this.player1);
        
        Node animNode = (Node) player1.getChild(0);
        animNode = (Node) animNode.getChild(0);
        
        animNode.removeControl(SkinningControl.class);
        animNode.removeControl(AnimComposer.class);

        player1.scale(100f);

First I opened it in the SDK and it appeared to not have any Bounds at all.

So I tried removing the SkinningControl, and that caused the model to shrink down to a very tiny size and become practically invisible (likely the size that was being used by the engine to re-calculate the incorrect bounds)

But scaling it back up by x100 made it visible and now the collisions are registering.

So it sounds the issue was something similar to what paul mentioned:

However I’m not sure then why changing hardware skinning didn’t fix it. But I don’t know much about that setting, and in my case I use the other solution:

But that does take more work to setup and probably isn’t the preferred solution for simple editor picking… but since changing the hardWareSkinning setting didn’t fix it, I’m unsure how else to solve the issue without having to remove the skinningControl.

1 Like

Thank you for taking the time to look at the sample app. Do you think I can fix this boundary issue in Blender? because, this is a model downloaded from Mixamo and its animations were assembled in Blender then it was exported as GLB

1 Like

Yeah I think it should be something you could fix in blender.

I think you’d probably want to try setting a new bind pose for the rig once at the correct scale, and also set the loc/rot/scale on the model and animControl again probably. And if that doesn’t fix it then I’d try adjusting or even removing some individual bones/joints that don’t have direct mesh influence. I know I’ve seen some models with weird nesting and multiple scaled/rotated joints just above the rootBone that might need scaled up and rotated to make the model stand upright.

1 Like

Yeah, I’m having doubts that the setting “took” in this case.

With hardware skinning turned off, what you see should be what you get… though each animated frame you will need to clear the collision data and bounding box and have it recalculated.