rapierrapier-3d

How do I detect collision events for sensors using the Rapier Kinematic Character Controller?


I am having trouble getting my Kinematic Character Controller (KCC) to ignore collisions with my sensor and I believe this is why collision events are not triggering. I tried changing the collision groups, but the character still seems to get pushed back by the sensor.

Here is how I create my controller with a collider and rigidBody:

// Create Capsule shape
let shape = new Capsule(0.25, 0.25);

// Create body/collider descriptions
let rigidBodyDesc = new RigidBodyDesc(RigidBodyType['KinematicPositionBased']);
let colliderDesc = new ColliderDesc(shape);

// Create body/collider from world
let body = world.createRigidBody(rigidBodyDesc);
let collider = world.createCollider(colliderDesc, body);

// Create Kinematic Character Controller
let controller = world.createCharacterController(0.01);

I then create the ground using similar functions:

// Create TriMesh shape
let shape = new TriMeshShape(vertices, indices, TriMeshFlags['FIX_INTERNAL_EDGES']);
let rigidBodyDesc = new RigidBodyDesc(RigidBodyType['Fixed']);
let colliderDesc = new ColliderDesc(shape);

// Create body/collider from world
let body = world.createRigidBody(rigidBodyDesc);
let collider = world.createCollider(colliderDesc, body);

Lastly, I create the sensor cube using the following code:

// Create Cuboid shape
let shape = new Cuboid(0.5, 0.5, 0.5);

// Create body/collider descriptions
let rigidBodyDesc = new RigidBodyDesc(RigidBodyType['Fixed']);
let colliderDesc = new ColliderDesc(shape).setSensor(true);

// Create body/collider from world
let body = world.createRigidBody(rigidBodyDesc);
let collider = world.createCollider(colliderDesc, body);

Assuming I get everything working, this should show collision events:

let events = new EventQueue(true);

function update() {
  // Compute world
  world.step(events);

  // Review events
  events.drainCollisionEvents(function(handle1, handle2, started) {
    console.log(handle1, handle2, started);
  });
}

Solution

  • Ignoring Sensor Collisions

    By design, the Kinematic Character Controller will not exclude colliders with the isSensor property set to true. You can exclude colliders with this property by adding the parameter QueryFilterFlags['EXCLUDE_SENSORS'] with your computeColliderMovement function.

    Note: I use Vite to build my applications, so you may need to include RAPIER before each function depending on your project. Ex: RAPIER.ActiveEvents['COLLISION_EVENTS']

    // Create vectors for movement
    let nextTranslation = new Vector3(0, 0, 0);
    let desiredTranslation = new Vector3(0, 0, 0);
    
    function update(delta) {
      // Reset downward velocity
      if (controller.computedGrounded()) desiredTranslation.y = 0;
    
      // Simulate gravity
      desiredTranslation.y -= delta;
    
      // Compute movement and update body position
      controller.computeColliderMovement(collider, desiredTranslation, QueryFilterFlags['EXCLUDE_SENSORS']);
      nextTranslation.copy(body.translation());
      nextTranslation.add(controller.computedMovement());
      body.setNextKinematicTranslation(nextTranslation);
    }
    

    Source: github.com/dimforge/rapier.js/issues/242

    Activate Events for Colliders

    The default value for all collider ActiveEvents enum is 'NONE', so you will need to enable this for your KCC collider if you wish to see any collision events in the queue.

    colliderDesc.setActiveEvents(ActiveEvents['COLLISION_EVENTS']);
    

    Source: rapier.rs/docs/user_guides/javascript/colliders

    Activate Collision Types

    Since both of your colliders are "non-dynamic", you will need to change the activeCollisionTypes property for your KCC collider if you wish to interact with Fixed types. The default enum value is 'DEFAULT', so you will need to set the active collision types to match your desired type (ex: 'KINEMATIC_FIXED'). If you want collision events to work on all collider types, you can use 'ALL' as your enum key.

    colliderDesc.setActiveCollisionTypes(ActiveCollisionTypes['KINEMATIC_FIXED']);
    

    Source: rapier.rs/javascript3d/enums/ActiveCollisionTypes.html

    Note: My answers were written for Rapier.js v0.14.0, so solutions may vary over time.