Godot Version
4.4.1 stable
Question
Hello, I’m working on a simple test project where one node orbits around a target node using a sphere curves motion, and continuously looks at the target. I’m encountering a classic problem that I can’t seem to solve: achieving smooth, continuous rotation that maintains horizontal orientation without gimbal lock.
The Setup:
One node orbits around a target node in a complex 3D spiral pattern
The orbiting node should always look at the target
The node should maintain horizontal orientation (its “up” vector should stay aligned with world Y-axis)
The Problem:
I have two methods in my update_continuous_look_at() function, but each has issues:
Method 1 (Current implementation):

var target_direction = (target.global_transform.origin - global_transform.origin).normalized()
var current_forward = current_rotation * (Vector3.FORWARD)
var delta_rotation = get_rotation_between_directions(current_forward, target_direction)
current_rotation = delta_rotation * current_rotation
current_rotation = current_rotation.normalized()
global_transform.basis = Basis(current_rotation)
func get_rotation_between_directions(from: Vector3, to: Vector3) -> Quaternion:
from = from.normalized()
to = to.normalized()
if from.is_equal_approx(to):
return Quaternion.IDENTITY
if from.is_equal_approx(-to):
# Find perpendicular axis for 180-degree rotation
var perpendicular = Vector3.UP
if abs(from.dot(perpendicular)) > 0.9:
perpendicular = Vector3.RIGHT
var axis = from.cross(perpendicular).normalized()
return Quaternion(axis, PI)
# General case: calculate rotation axis and angle
var axis = from.cross(to).normalized()
var angle = from.angle_to(to)
return Quaternion(axis, angle)
Smooth, continuous rotation without gimbal lock
Doesn’t maintain horizontal orientation - the node can roll/tilt
Method 2 (Commented out):

var target_direction = (target.global_transform.origin - global_transform.origin).normalized()
global_transform.basis = Basis.looking_at(target_direction)
Maintains horizontal orientation perfectly
Suffers from gimbal lock - when the node passes directly above or below the target, it flips/snaps
What I’m trying to achieve:
- Continuous, smooth rotation without sudden flips or snaps
- The node’s “up” vector should always point toward world Y+ (maintain horizontal level)
- No gimbal lock when the node passes above or below the target
- When the node is directly above the target looking down, its “forward” direction should naturally rotate without the node rolling
I’ve tried various approaches including quaternion SLERP, decomposing rotations into yaw/pitch components, and different basis construction methods, but I always end up with either gimbal lock or loss of horizontal orientation.
Has anyone solved this problem before? Any suggestions for maintaining both continuous rotation AND horizontal orientation?
Here’s my minimal Godot project for reference: https://drive.google.com/file/d/1a4Pf0cUqFLXx47PMfKQX8AzYpbQkbGN5/view?usp=sharing
Thank you for any help!