Layer-based raycast?

Hey, is there any way to do raycasting ignoring some entities in the middle?

I saw this thread existed in 2016 but there was not any way to achieve this: How to Create a Ray with Ignore Collision Entity? Or Multi Hit Result

Has this changed nowadays? Or we still can’t ignore entities based on layer or something?

This seems like a must-have feature to me :frowning:

1 Like

The ammo/bullet API allows you to assign physics objects to groups and have them collide according to a mask. This can also be used with raycasting although none of this is exposed in the PlayCanvas API.

A project that shows how to use the groups can be found here: https://playcanvas.com/project/519294/overview/physics-mask

The minified code from Virtual Voodoo for the raycast is here:

    var n = new Ammo.btVector3
      , t = new Ammo.btVector3
      , e = function(n, t, e) {
        this.entity = n,
        this.point = t,
        this.normal = e
    };
    pc.RigidBodyComponentSystem.prototype.raycastFiltered = function(o, i, r, a) {
        n.setValue(o.x, o.y, o.z),
        t.setValue(i.x, i.y, i.z);
        var l = new Ammo.ClosestRayResultCallback(n,t);
        l.set_m_collisionFilterGroup(r),
        l.set_m_collisionFilterMask(a),
        this.app.systems.rigidbody.dynamicsWorld.rayTest(n, t, l);
        var s = null;
        if (l.hasHit()) {
            var u = l.get_m_collisionObject()
              , c = Ammo.castObject(u, Ammo.btRigidBody)
              , m = l.get_m_hitPointWorld()
              , d = l.get_m_hitNormalWorld();
            c && (s = new e(c.entity,new pc.Vec3(m.x(),m.y(),m.z()),new pc.Vec3(d.x(),d.y(),d.z())))
        }
        return Ammo.destroy(l),
        s
    }
1 Like

Thanks I will test this out on monday

Can this be implemented without Rigidbodies? Raycast works against plain Colliders, and I don’t need Rigidbodies for anything.

Edit: okay forget it I didn’t see you already implemented it without rb.

Btw is there any reason why this isn’t documented or implemented by the PlayCanvas team if they see it’s working great?

Just to update the thread.

The difficulty here was to assign the custom group to the collider as it is not exposed in the same way as the rigidbody.

In the end, I had to remove the body from the world and re-add it with the desired group. eg (where flags represent the custom groups)

    // Ugh
    this.app.systems.rigidbody.removeBody(body);

    // set the body's activation state to disable simulation so
    // that it properly deactivates after we remove it from the physics world
    body.forceActivationState(pc.BODYSTATE_DISABLE_SIMULATION);

    this.app.systems.rigidbody.addBody(body, pc.BODYGROUP_TRIGGER | flags, pc.BODYMASK_NOT_STATIC ^ pc.BODYGROUP_TRIGGER);

    // set the body's activation state to active so that it is
    // simulated properly again
    body.forceActivationState(pc.BODYSTATE_ACTIVE_TAG);

    body.activate();

    this.entity.trigger.syncEntityToBody();
2 Likes

i guess im a bit confused as to how this would work with raycasting collision with no rigidbody.

How would that implementation happen?

Well, basically, collision volumes are enough to calculate if there’s a hit or not. Rigidbodies only enable the collision volumes to behave like a physical object in the world (gravity influence, external forces influence… etc).

I have a working implementation on a few projects that @yaustar helped me to put together, I will try to release a public project with both things working, thought I’ve had some issues with performance when using custom user layers, so I’m not sure if I’ll be able to polish it anytime soon.

In any case, I’ll just put the project yaustar and I worked on together public.

1 Like

My raycast only hit entities with maskAll enabled. :sob:

You can now use raycastAll and filter the resulting array to only get the results on the layer you want.

Hay @devMidgard! How did you do that? Why is that not working with raycastFirst (or in my case with raycastFirstByTag made by @yaustar).

Because that code is old.

code would be something like this (untested):

var results = this.app.systems.rigidbody.raycastAll(from, to);
var filtered = results.filter(elm=> elm.tag === 'sometag');
for(var i = 0; i < filtered.length;i++){
   console.log(filtered[i].name);
}

raycastAll is a new feature that was added by @will on a recent update, like a month ago. Pretty useful as you can see.

Docs: https://developer.playcanvas.com/en/api/pc.RigidBodyComponentSystem.html#raycastAll