Selective Raytracing

Hey Monkeys,

First off: I know that jme’s built in ray tracing uses BVHs and hence it’s a good idea to build it on the Scenegraph, however for my case, I’d want to exclude the high-detail character meshes and only collide my hitboxes and the world.

For this, I’d need a way to specify which geometries to collide with. A possible solution would be to temporarly add all the spatials to a new Node and then add them back to their origin, but that’s a really bad solution to me.

Do you have any proper suggestions for that maybe?

You could try setting a .setUserData() flag on certain objects to sort them into collision groups, and then check the user data when you do the raytracing.

In my game I flag each object with a user data key like “ambient” or “physicsObject”, then when I need to do ray tracing I loop through the CollisionResults list and return the object that’s closest and also has a non-null value set for the user data key that corresponds with the collision group I want to collide with.

1 Like

Yes, and pointless to go through all of that trouble just to avoid traversing yourself.

In the cases where I’ve wanted custom collision traversing then I just traverse myself. It’s super simple and then I can ignore/follow scene graph branches using whatever logic I want.

I tend to use custom nodes and override the collideWith method to return 0 when I want to them to be always skipped, collide with some hitbox instead or anything that needs to be adjusted, like skipping a few children.

I think we need to add some “filter interface” as a third optional argument to the method “collideWith()”, it will be better option.

Well… the rest of the engine works with “hints” set on the spatial, CullHint, BatchHint, ShadowMode etc… IMO we should add a CollideHint.

4 Likes

The problem is that it needs a deeper design so we don’t just end up hacking around it again. For example, if the control is supposed to be our way to “extend” a spatial then why isn’t it involved in things like collision?

At one point, I started to think what we really needed was something like “hooks”. Instead of having some monolithic control that has to get called for everything maybe have a way of hooking update or hooking render or hooking collision… but otherwise nothing happens (except some default behavior in case of collision maybe). Or there would be default hooks that could get overridden. Even culling may want to hook into this I guess.

See, a hint may not be good enough. What if I want some things to be collided now and different ones later. So maybe a mask? Well, what if the mask is not convenient for the data I have and I’d rather have real objects and a function to compare.

Then again, maybe an on/off inherited hint like culling would be fine, too. After all, we’ve gotten by with “nothing at all” for a long time now. :slight_smile:

Well, I’m open to à new design, but a collision hint seems like a quick solution that would resolve the problem at hand.

Reworking the control paradigm sounds like jme4 to me :stuck_out_tongue:

The problem is that it’s only one way to solve it and then we have to support it forever.

Yes. It’s part of my “what would JME 4 look like” ideas.

Another option is to show how to do it with a scene graph visitor and perhaps even move collision detection out to a predefined visitor and just use the collideWith() method as a convenient wrapper.

Either what we say is true and you could implement your own visitor easy enough or we’d have to fix some things to make it work. And in either of those case, the end result is probably the “right answer”.

So as it has already been said: A hint might not be appropriate enough because you might have to traverse the scenegraph multiple times per frame (e.g. one raytrace for all “interactibles”, one raytrace for the weapons, maybe additional raytraces for the AI (Unreal calls them Environment Queries).

Actually it would also be awesome if these methods could be multithreaded then, so you could e.g. use the stream api to use all cores (the bvh tree only has to be built once per frame (or even less when nothing changed)).

@yaRnMcDonuts 's approach works, however it does trace the whole hi-poly geometry at might not be that appropriate then.

What I have up now is the following code, however it sometimes doesn’t seem to collide as expected (but I didn’t find the time to do a test case, so maybe it wouldn’t work with regular raycasting as well).

/**
     * This is used internally to see if the spatial s is inside the camera frustum.<br>
     * Thus it is used to prune elements being too far away or too close.<br>
     * 
     * @param s The Spatial to check
     * @param cam The Camera to use
     * @return Whether the Spatial is inside the Camera Culling or not
     */
    public static boolean CheckCulling(Spatial s, Camera cam) {
        BoundingVolume bv = s.getWorldBound();
        int planeState = cam.getPlaneState();
        cam.setPlaneState(0);
        Camera.FrustumIntersect result = cam.contains(bv);
        cam.setPlaneState(planeState);

        return (result != Camera.FrustumIntersect.Outside);
    }
    
    /**
     * Perform a raycast on spatials against other.
     * 
     * @param spatials The spatials to consider
     * @param other The "other" (Ray, Collidable)
     * @param results The result variable
     * @return The number of collisions found.
     */
    public static int CollideWith(Stream<Spatial> spatials, Collidable other, CollisionResults results) {
        int total = 0;
        total = spatials
            .filter((s) -> (RaycastUtil.CheckCulling(s, Main.self.getCamera())))
            .map((s) -> s.collideWith(other, results)).reduce(total, Integer::sum);
        
        /* Before Functional Operator:
        for (Spatial s: spatials) {
            if (RaycastUtil.CheckCulling(s, Main.self.getCamera())) {
                total += s.collideWith(other, results);
            }
        }*/
        return total;
    }
    
    /**
     * Cast a ray against a set of spatials.
     * @param ray The ray to cast
     * @param against The stream of spatials
     * @return The results
     */
    public static CollisionResults cast(Ray ray, Stream<Spatial> against) {
        CollisionResults res = new CollisionResults();
        int num = CollideWith(against, ray, res);
        return res;
    }

So the code is actually really simple, the only thing I could imagine is that some bvh caching or comparable is the problem (however @sgold fixed some phantom triangle collissions lately?)

Since BVH is based on triangles, it is easily confused by meshes that don’t consist entirely of triangles. I fixed a bunch of cases back in August, and that fix was included in JME 3.2:

collideWith() sometimes reports collisions with phantom triangles · Issue #710 · jMonkeyEngine/jmonkeyengine · GitHub

I believe there are still issues with hybrid meshes and other exotic mesh modes, but I doubt that’s your problem. Did you remember to disable hardware skinning?

Kind of:
I have HW Skinning on but I am using an attachement node to translate the (blender-generated) capsule, which is essentially a stretched sphere.

Xbuf should’ve converted them into triangles, I guess, but yeah, without a test case everything might be only guess work.