Smoothly rotating towars a point (in 3D)

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

How can I rotate a mesh to face a point, but not instantly? I would like to make my characters face the destination point before walking, but in a perceptible way.

:bust_in_silhouette: Reply From: Magso

I answered a similar question here.

This is the script to smoothly look at a point.

var child_look_at
export var accuracy = 1.0
onready var target = get_parent().get_node("Target") 

func _ready():
    child_look_at = Position3D.new()
    add_child(child_look_at)

func _process(delta):
    child_look_at.look_at(target.global_transform.origin, Vector3.UP)
    var target_rotation = Quat(child_look_at.global_transform.basis)
    var current_rotation = Quat(global_transform.basis)
    var next_rotation = current_rotation.slerp(target_rotation, delta*accuracy)
    global_transform.basis = Basis(next_rotation)

However it causes rigidbodies to act a little strange, so if somebody knows how to do it using add_torque() use that way.

:bust_in_silhouette: Reply From: nickglenn

I was struggling with this too and found the following approach seems to work alright. It’s similar to the other answer posted, but without the need for an additional node. I’m still working on a better version with proper maths, rather than the “cache, set, set again” method I have happening here.

My answer is in C#, but translating to GDScript should be trivial.

// cache the current rotation
var rotation = new Quat(Rotation);

// use LookAt to look at the desired location
LookAt(targetPosition, Vector3.Up);

// cache the new "target" rotation
var targetRot = new Quat(Rotation);

// use Quat.Slerp to perform spherical interpolation to the target rotation - a weight like 0.1 works well - then set the rotation by converting the Quat back to a Euler
Rotation = rotation.Slerp(targetRot, weight).GetEuler();

Yoo, thank you soooooo much! This is exactly what I was looking for! Had to translate it to GDScript, but it was pretty easy to do so. Here is the code in GDScript if anyone wants it.

#cache the current rotation
var rot = Quat(rotation)
# use look_at to look at the desired location
look_at(target_pos, Vector3.UP)
# cache the new "target" rotation
var target_rot = Quat(rotation)
#use Quat.Slerp to perform spherical interpolation to the target rotation
#a weight like 0.1 works well
#then set the rotation by converting the Quat back to a Eule
rotation = rotation.slerp(target_rot, weight).get_euler()

skullleeep | 2022-01-29 17:01

:bust_in_silhouette: Reply From: jeudyx

This is the solution:

(sample project is 3d Rotate Direct Constant Smooth - Godot Asset Library).

I just tried and works perfectly.