Rotation goes backwards if angle is bigger than 180 Degrees

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

There has already been a similar question, yet no answer: Lerp rotation above 180 degrees

By default 360 degrees are from -180 to +180. For example, when I am rotating with tweens interpolate_property from -160 to +160 (which in theory is 40deg difference) instead the engine chooses to go all the way around and rotate 320 degrees. Is there any method that could help me rotate by shortest path?

This is my current code:

func turn_to_smooth(target_direction: Vector3):
    dummy_direction.turn_to(target_direction)
    var from = rotation_degrees
    var to = dummy_direction.rotation_degrees

    TweenNode.interpolate_property(
        self,
        "rotation_degrees",
        from,
        to,
        1,
        Tween.TRANS_LINEAR, 
        Tween.EASE_IN_OUT
    )

    TweenNode.start()

See this article in the docs for help:
Using 3D transforms — Godot Engine (3.1) documentation in English

The solution for your problem should be “Interpolation with quaternions”:
Using 3D transforms — Godot Engine (3.1) documentation in English

wombatstampede | 2019-10-25 07:42

The question you are citing says that you should use radians instead of degrees, if you want to allow values greater than 180 (=PI). Have you tried with radians? If you can have values greater or lower than PI, you can check which way to move by using min(angle_dif_a, angle_dif_b), where angle_dif_b would be 40, and a 320.
I think this has a similar solution (look for zylann’s answer)
https://forum.godotengine.org/5770/how-to-lerp-between-two-angles

gmaps | 2019-10-25 07:54

Yes I have tried it with Radians - in a nutshell it does completely the same thing.
My tween interpolate_property still goes the longer path.

“you can check which way to move by using min(angledifa, angledifb),”
How does that help me? What method should I use to move that path?
What would happen next time? because if I move from -340 to -400 the original rotation is already ruined

Ankeris | 2019-10-25 08:13

After insight of wombatstampede
Not yet sure how this is working - tho it solved my problem. I will do my research but this is my current solution:

func turn_to_smooth(target_direction: Vector3):
    dummy_direction.turn_to(target_direction)


func _physics_process(delta):
    var from = Quat(transform.basis)
    var to = Quat(dummy_direction.transform.basis)

    # find halfway point between a and b
    var c = from.slerp(to, 0.1) 
    transform.basis = Basis(c)

Ankeris | 2019-10-25 10:50

:bust_in_silhouette: Reply From: wombatstampede

I’m just copying my comment here to indicate that there’s been an answer to your question which led to a solution (by you).
My comment:

See this article in the docs for help:
Using 3D transforms — Godot Engine (3.1) documentation in English

The solution for your problem should be “Interpolation with
quaternions”:
Using 3D transforms — Godot Engine (3.1) documentation in English

Please see the comment for Ankeris above for the specific solution.

Quat resets scaling of my object, but I could just put a Spatial element as a parent and have a script on it

Github issue

Ankeris | 2019-10-26 19:32

Ok, obviously you solved it somehow that way. :slight_smile:

I just did a short test. And the scale is reflected as a factor (somehow) in transform.basis. It seems that Quat normalizes the vectors (to 0…1) and therefore resets the implicit scale back to (1,1,1).

Personally I find it a bit misleading that this isn’t visibly shown in the “Matrix” in the Spatial Inspektor which seems always normalized.

Probably you can re-apply the scale in each assignment. I didn’t test it but the changed assignment might look like this:

transform.basis = Basis(c).scaled(scale)

wombatstampede | 2019-10-28 07:21