Camera does a strange rotation on cursor lock

I am using cursor lock code when a mouse is pressed and display the cursor back when the mouse is released.

canvas.onpointerdown = () => {
    canvas.requestPointerLock();

};
canvas.onpointerup = () => {
    document.exitPointerLock();
};

I am using an example here - https://playground.babylonjs.com/#GVPILZ#4

When you keep rotating the camera with mouse, at some point, the camera rotates rapidly to some other angle. This happens quite a number of times. It is related to the mouse lock/unlock.

Here is also a video demonstrating it - 2023-02-17 09-43-25

How can i fix this?

cc @PolygonalSun

1 Like

I have reuploaded the video because it got expired. Please let me know if something is not clear.

I can take a look and see what’s going on.

2 Likes

Hi again, was there any luck figuring out the issue?

He is a bit full of tasks recently but he’ll look over this as soon as he can :sweat_smile:

Sorry, I meant to update this yesterday. When I was looking at this, I was able to repro this by performing a quick flick action with the mouse. I haven’t found the root cause yet but I suspect that the behavior could be caused by the difference between how camera movement is handled when in and out of pointer lock. With pointer lock, the cursor absolute locaiton is not updated with each movement but the deltas (movementX/Y) are so we use that for movement. I’m currently digging into the code that checks for pointer lock to see if there might be some race issue. As far as a fix or workaround, nothing comes to mind but I’ll let you know when I find something.

3 Likes

Thanks a lot for taking a look into this. Appreciate it.

I haven’t been able to figure it out yet but if you only need to rotate around a given point while in pointerlock, you could try removing the original pointerlock code and attachControl call and using a custom approach:

scene.onPointerObservable.add((eventData) => {
        const event = eventData.event;
        const type = eventData.type;

        switch(type) {
            case BABYLON.PointerEventTypes.POINTERDOWN:
                canvas.requestPointerLock();
                break;
            case BABYLON.PointerEventTypes.POINTERUP:
                document.exitPointerLock();
                break;
            case BABYLON.PointerEventTypes.POINTERMOVE:
                if (document.pointerLockElement === canvas && event.buttons >= 0) {
                    camera1.inertialAlphaOffset -= event.movementX / camera1.angularSensibilityX;
                    camera1.inertialBetaOffset -= event.movementY / camera1.angularSensibilityY;
                }
        }
    });

Example in PG
This might be a good alternative and eliminate the random back spinning.

1 Like

Thank you for your response and an alternate solution. I tested the PG but I am still facing the same problem.

Pinging @PolygonalSun just for visibility

I found the root cause! Sorry that this took so long but this was a really evasive bug. So, the issue here is that we use the pointerlockchange event to update when we’re in a pointer lock. Unfortunately, this event fires AFTER canvas.onpointerup executes. Because of this, the pointerlock is released, as far as the browser is concerned and will report a new movement delta (movementX/Y) based off of the (now released) location. This is why there’s a massive movement it a different direction than expected.

I have a fix that I’m testing and if I can’t find any issues, I’ll go ahead and create a PR for it. I’ll let you know when that’s live.

2 Likes

PR is live: Engine: Modified isPointerLock to update when called instead of during pointerlockchange event by PolygonalSun · Pull Request #13650 · BabylonJS/Babylon.js (github.com)

2 Likes

PR is merged

Thanks a lot for finding the problem and fixing it :slight_smile: Appreciate it.

1 Like