Weird lerp rotation behavior

I’m working on my player controller with R3F and Rapier, and I’m trying to handle rotations the following way to make them smooth:

if (leftward) {
    const targetRotation = Math.atan2(cameraDirection.z, -cameraDirection.x)
    playerPrimitive.current.rotation.y = THREE.MathUtils.lerp(
        playerPrimitive.current.rotation.y,
        targetRotation,
        lerpAmount
    );
    playerPrimitive.current.rotation.y += rotationSpeed;
    playerRigidBody.current.setLinvel(velocity, true)
}

The above code is inside the useFrame()

The issue is that I’m getting the following behavior:

ezgif.com-video-to-gif (2)
You can see at the end of the GIF how the player starts to move weirdly, and that is being caused by the lerp. Ideally I’d like to avoid using modulo as well.

How can I fix this issue?

Cheers!

Lerping angles is risky, because angles do not have unique numerical representation, e.g. 10° = 370°. If you want to avoid modulo (I have no idea why, is it too scary to use it?) you can lerp directions, not angles. Just do not forget to normalize the resulting vector and hope that you will never lerp between two perfectly opposite vectors.

Another approach is to use quaternions. It is said that they provide almost risk-free rotation.

2 Likes

Pavel, thank you for the suggestions. Quaternions did the trick, and beautifully.

I appreciate the detailed answer and illustration.

1 Like

btw i would suggest you try GitHub - pmndrs/maath: 🪶 Math helpers for the rest of us

this is in my opinion better than lerping because it has velocity and is therefore interruptible, but dampE is also overflow safe, it takes the shortest path between two angles. it has quaternion damp as well. for anything that takes input i would prefer it over lerp, especially when you change directions quickly because it will at least have some momentum, a little similar to how spring physics work.