Why doesn't my Basis.slerp() take the closest path?

Godot Version

V4.2.2

Question

Why doesn’t my Basis.slerp() take the closest path ?

To demonstrate, I made a example scene with a node that rotates from the back to the top. A rod is there to show the precise movement.

The code of the Sphere node is :

extends MeshInstance3D

var timer = 0
var top = true

var goal_basis: Basis

@onready var rot: Node3D = $RotatingNode

func _process(delta: float) -> void:
	timer -= delta
	if timer <= 0:
		timer = 3
		if top:
			top = false
			print("Facing back")
			goal_basis = Basis.looking_at(Vector3.BACK)
		else:
			top = true
			print("Facing top")
			goal_basis = Basis.looking_at(Vector3.UP, Vector3.LEFT) # Specify an "up" vector different than the direction
		print(goal_basis)
	rot.basis = Basis(rot.basis.slerp(goal_basis, 0.02))

I can’t upload videos, so here’s some screenshots.



For the record, I also tried to use Quaternions, as by the doc :

For practical use, it’s enough to understand that pretty much their main use is doing a closest path interpolation.

To no avail : it behaved the same as the current scene. I used get_rotation_quaternion() on every basis to get those.

What happens if you use your timer as the weight?

var top_basis := Basis.looking_at(Vector3.UP, Vector3.LEFT)
var back_basis := Basis.looking_at(Vector3.BACK)

var clamped_timer := clampf(timer, 0, 1)
rot.basis = back_basis.slerp(top_basis, clamped_timer)

I edited my function to try that.

func _process(delta: float) -> void:
	timer -= delta
	if timer <= 0:
		timer = 1
		if top:
			top = false
			print("Facing back")
			goal_basis = Basis.looking_at(Vector3.BACK)
		else:
			top = true
			print("Facing top")
			goal_basis = Basis.looking_at(Vector3.UP, Vector3.LEFT) # Specify an "up" vector different than the direction
		print(goal_basis)
	#rot.basis = Basis(rot.basis.slerp(goal_basis, 0.02))
	var clamped_timer: float = 1 - clampf(timer, 0, 1)
	rot.basis = rot.basis.slerp(goal_basis, clamped_timer)

But as expected, it only changes the timing of the movement : it becomes linear.

one key difference I should’ve pointed out is not using rot.basis.slerp I used back_basis.slerp.

Using lerp/slerp on a shifting starting point might cause issues.

Ohh, nice point. But I get the same result with :

@onready var rot: Node3D = $RotatingNode
var previous_basis: Basis
var goal_basis: Basis

func _process(delta: float) -> void:
	timer -= delta
	if timer <= 0:
		timer = 1
		if top:
			top = false
			print("Facing back")
			previous_basis = rot.basis
			goal_basis = Basis.looking_at(Vector3.BACK)
		else:
			top = true
			print("Facing top")
			previous_basis = rot.basis
			goal_basis = Basis.looking_at(Vector3.UP, Vector3.LEFT) # Specify an "up" vector different than the direction
		print(goal_basis)
	#rot.basis = Basis(rot.basis.slerp(goal_basis, 0.02))
	var clamped_timer: float = 1 - clampf(timer, 0, 1)
	rot.basis = previous_basis.slerp(goal_basis, clamped_timer)

Huh, maybe it has to do with the look_at possibly rotating to face a different way that we can’t tell with the cylinders.

See if changing this line from Vector3.LEFT to RIGHT, FORWARD, or BACK results in a different rotation

var top_basis := Basis.looking_at(Vector3.UP, Vector3.LEFT)
1 Like
goal_basis = Basis.looking_at(Vector3.UP, Vector3.RIGHT)

This makes the curve at the left side of the ball, while it was at the right side before.

goal_basis = Basis.looking_at(Vector3.UP, Vector3.FORWARD)

This makes the movement perfect, exactly as wanted.

goal_basis = Basis.looking_at(Vector3.UP, Vector3.BACK)

This makes an even more exaggerated curve on the left.

How can I interpret that ?
Later, those target basis will be completely dynamic, so I have to find an explanation to have a consistant behavior.

Remember you are also rotating the UP vector. Add another cylinder to represent that up axis, it should be more clear with that visual aid

1 Like

Thank you for your help ! It’s more clear now.

I still want to choose the direction of my up vector, without it affecting the main rotation.
But I think I can manage it with several layers of rotation in children.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.