Mouse pointer lock and OnPickTrigger

Hey @vx9,
So I took a look at your PGs (particularly, the second one), and here’s what I’m seeing. You have an action set up to handle a pick when it happens, as well as performing a manual pick on a pointerdown event. Inside of scene.onPointerDown, you process the trigger if you get a hit on your sphere. When you enter a Pointer Lock, you’ll have one of two scenarios.
1.) If you click on anything that isn’t the sphere to start your pointer lock, it should work as expected because the ray is firing where you want it to fire.
2.) If you click on the sphere to start your pointer lock, your action will double activate.

The reason for scenario 2 is because when you request a pointer lock, any pointer events fired during that lock will not change the absolute coordinates in the pointer event. Only deltas (movementX/Y) will be updated. This means that every click you perform will be done at the exact same place, as far as the browser is concerned.
For the action OnPickTrigger, this action will automatically be processed as part of the “behind the scene” work between the InputManager and the ActionManager (this happens during the pointerup step). With this in mind, you’re processing your trigger from your down event and then potentially processing another with your up event.

To fix this, you’ll either need to not use the ActionManager and just work within either the callback or observable OR you can just create a boolean to skip the trigger body:

// Some boolean to track when to skip
var skipPick = false;
...
// Inside of your Action
sphere.actionManager.registerAction(
    new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPickTrigger, function(){
        if (!skipPick) {
            console.log("clicked using pickTrigger");
            sphere.position.x += 0.1;
        }
    })
);

// Using onPointerObservable just as a way to organize scene inputs
// If you use this, you will need to remove your onPointerDown code
  scene.onPointerObservable.add(eventData => {
      const e = eventData.event;
      if (e.button === 0) {
          if (eventData.type === BABYLON.PointerEventTypes.POINTERDOWN) {
                let hit = castRay(scene);
                if (hit.pickedMesh && hit.pickedMesh.name === "sphere") {
                    console.log("clicked on sphere using ray", hit.pickedMesh.name)
                    sphere.actionManager.processTrigger(BABYLON.ActionManager.OnPickTrigger)
                }
                skipPick = true;
          }
          // This just handles the up event, if you want you could just add this part to an onPointerUp callback and keep your down callback
          else {
              skipPick = false;
          }
      }
// As a note, this mask just makes it so we only do something for UP or DOWN only
  }, BABYLON.PointerEventTypes.POINTERDOWN | BABYLON.PointerEventTypes.POINTERUP);

Keep in mind, this is just one approach but hopefully this helps.

3 Likes