Lerp rotation with above 180 degrees difference

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By selamba

if is_moving: end_angle = input_movement_vector.angle() + deg2rad(90) $MeshInstance.rotation.y = lerp($MeshInstance.rotation.y, end_angle, 0.08)

The following code smoothly rotates a mesh from its current position to end_angle, which is dependant on input and only updates if buttons are being pressed, so that the mesh can finish its smooth rotation even when there is no input.

input_movement_vector updates as follows: “W” corresponds to positive Y (negative Z in 3D), and “D” to positive X. When any of the WASD buttons are pressed, this vector’s components update accordingly and get normalized. If no buttons are being pressed, it’s set to 0. It is completely independent from the Mesh’s rotation.


Now here’s the issue:
When I try to rotate from left to down (from A to S, or from A to A+S) and vice versa, instead of perfomring a smooth rotation in the correct direction, the mesh instead rotates in the opposite direction, preforming almost a full 360 degree rotation.

I have tried using linear_interpolate with rotation vector and input_movement_vector, didn’t help. Tried writing special cases for specific button inputs or rotation angles, couldn’t figure out how to rotate smoothly in the right direction. I would like to recieve help with the matter, or know the cause of the problem at least.

:bust_in_silhouette: Reply From: selamba

I solved the problem. I used the methods set_rotation() and atan2() instead of lerp. Here’s the final code:

if is_moving:
	var angle = atan2(hvel.x, hvel.z)
	var rotation = self.get_rotation()
	rotation.y = angle
	self.set_rotation(rotation)

where hvel is horizontal velocity in 3d space

That won’t be lerping anymore, I guess.
Also:

var rotation = self.get_rotation()
rotation.y = angle
self.set_rotation(rotation)

can be shortened to just:

rotation.y = angle

Dlean Jeans | 2019-07-13 17:23

:bust_in_silhouette: Reply From: Dlean Jeans

Use this if you wanna lerp between angles:

static func lerp_angle(from, to, weight):
    return from + _short_angle_dist(from, to) * weight

static func _short_angle_dist(from, to):
    var max_angle = PI * 2
    var difference = fmod(to - from, max_angle)
    return fmod(2 * difference, max_angle) - difference
:bust_in_silhouette: Reply From: BraindeadBZH

Say no to Euler angles