How do I stop rotation from switching from positive to negative and vice versa? (3D)

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

First, here is my goal:

I want a 3D orthographic camera to “tweenly” rotate (by user control) around a pivot point that is parented to the player avatar (In this case, a ship. But that isn’t important.) The intended effect is something like a 2D isometric game with full camera rotation. To be clear, this is all 3D made to look almost like 2D.

Here is my problem:

When the pivot point crosses over from positive to negative the Tween node flips the camera around in the opposite direction. In degrees; it switches from 180 to -180 and when I do it in radians; it switches from π to -π (obviously). When that crossover from positive to negative happens, the camera does (almost) a full spin. The camera should just cross over that positive/negative boundary without going back the other way. Hopefully, that makes enough sense that someone out there knows what I’m talking about.

Here is my node graph:

Player (Spatial)

	Ship (RigidBody)

		CameraRig_0 (Position3D)
	
	CameraRig_1 (Position3D)

		CameraTween_1 (Tween)
	
		CameraRig_2 (Position3D)
	
			CameraTween_2 (Tween)
		
			Camera (Camera, set as "Current")

		CameraRig_2_Target (Position3D)

“Ship” has code that is not pertinent to the camera other than its coordinates, which are taken from its child “CameraRig_0”.

“CameraRig_1” has this code:

extends Position3D

export var tween_time = 0.05

onready var cam_tween = get_node("CameraTween_1")

func _process(delta):

	var strt_vect = self.global_transform.origin
	var tgt_vect = $"../Ship/CameraRig_0".global_transform.origin

	cam_tween.interpolate_property(self, "translation", strt_vect, tgt_vect, tween_time, Tween.TRANS_BOUNCE, Tween.EASE_IN)
	cam_tween.start()

That code works (for whatever reason) to make the camera follow the ship in a way that feels right. Now, on to the problem areas involving rotation. “CameraRig_2” has this code:

extends Position3D

export var tween_time = 0.1

onready var cam_tween = get_node("CameraTween_2")

func _process(delta):

	var strt_rot = self.rotation
	var tgt_rot = $"../CameraRig_2_Target".rotation

	#debugging:
	print(tgt_rot) # Problem: Target switches from positive to negative so the tween flips around.

	cam_tween.interpolate_property(self, "rotation", strt_rot, tgt_rot, tween_time, Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
	cam_tween.start()

And then the simplest part: “CameraRig_2_Target” has this code:

extends Position3D

var cam_rot_spd = 0.03

func _process(delta):

	if Input.is_action_pressed("h_camleft"):
		rotate_y(cam_rot_spd)
	
	if Input.is_action_pressed("h_camright"):
		rotate_y(-cam_rot_spd)

I could just use that last code and it would work just fine. But I want to be able to use the tweening without worrying about the tweening going in the wrong direction and creating that undesirable “spin” effect.

I’m sure that someone out there knows what I am trying to do, and they also know that I’m going about it in a ‘bass-ackwards’ way. I just need someone out there to set me on the right track.

Here is a link to a gif that will probably make the problem easier to understand:

https://photos.app.goo.gl/h3Dfz3ukdMdjqY5P6

CeanHuck | 2021-01-20 11:42

:bust_in_silhouette: Reply From: Andrea

from the docs:
Tween: Smoothly animates a node’s properties over time.

i think that by definition you cannot do value jumps with tweens, as they are made to interpolate 2 values, if one is positive and the other is negative, they will lineary go from positive to negative.
either you never reset the angle, or you do it in one frame, something like

if rotation>180:
 rotation-=180

You’re right. Tweening was not what I wanted to use. (I’m still new to this.)

What I really wanted was ‘slerping.’ I found this page in the docs:

Using 3D transforms — Godot Engine (latest) documentation in English

I basically used that exact same code and it worked great!

extends Position3D

export var slerp_amount = 0.2

func _process(delta):
	
	var strt_rot = Quat(self.transform.basis)
	var tgt_rot = Quat($"../CameraRig_2_Target".transform.basis)
	var slerp_to = strt_rot.slerp(tgt_rot,slerp_amount)
	transform.basis = Basis(slerp_to)

CeanHuck | 2021-01-28 05:15

i actually have to thank you, i didnt know about the slerp function and it’ll be very usefull for my project :slight_smile:

Andrea | 2021-01-28 08:39