Rotate 90 degrees smoothly

I’m working on a script that will rotate an object 90 degrees. Here’s what I’ve got. I have been looking into it for a little while now and this is the most functional thing I created. I could use some help.

When I press Q or E the object just rotates in a jerking motion X amount of degrees depending on how high I put my turnSpeed. AND also the rotation only limited to +90 through -90 degrees. I want to be able to fluidly go in a full circle in 90 degree intervals. I was under the impression that Quaternion.Lerp would create a smooth rotation?

Could someone give me a hand?

P.S. I have tested it without the transform.rotation.y inside my Quaternion.Euler parameters and I get the same result.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewScript : MonoBehaviour
{
    public float turnSpeed = 1f;
    private Quaternion rotation = Quaternion.identity;
  

    // Start is called before the first frame update
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {
        float rotateDir = Input.GetAxisRaw("CameraRotate");
        rotation = Quaternion.Euler(0, transform.rotation.y + (90 * rotateDir), 0);

        if(rotateDir == 1)
        {
            Debug.Log("Turning right");
        }
        if(rotateDir == -1)
        {
            Debug.Log("Turning left");
        }

        if(Input.GetKeyDown(KeyCode.Q) || Input.GetKeyDown(KeyCode.E))
        {
            transform.rotation =  Quaternion.Lerp(transform.rotation, rotation, turnSpeed * Time.deltaTime);
        }
    }
}

It’s because you’re using Lerp. And there is a proliferation of tutorials, and even the unity docs, that push Lerp out there without explaining what it actually does but rather implying it gives a smooth transition from 1 value to another but not what that curve looks like.

Lerp, or linear interpolation, is basically this:

float Lerp(float a, float b, float t)
{
    return (b - a) * t + a;
}

note - this is an unclamped lerp, and it’s for a float. Actually unity clamps their t from 0-1, and you’re using a Quaternion. But the concept is basically the same.

It’s effectively Zeno’s Paradox: Achilles and the tortoise:
https://en.wikipedia.org/wiki/Zeno’s_paradoxes

Every Update you’re moving t towards your target. Where t is a percentage represented as 0->1. So if you pass in 0.5, you get back a value halfway between start and end. 0.9 and you get a result very close to the end. You keep doing this over and over moving ‘t’ of the distance between you and the goal never actually reaching it… just closing ever smaller gaps one after the other.

Your motion over time looks like:

But if you stick in 1 for t, you actually close the entire gap. Larger than 1 you pass the total (this is why unity clamps your lerp).

Thing is you’re using “turnSpeed * Time.deltaTime” which is so unmeaningful of a value. The ‘t’ in Lerp is not a speed, it’s a percentage. And you’re passing in variable noise pretty much. And I know… you probably got that from a tutorial or even the unity docs. And I honestly don’t know WHY people use that. It’s so unintuitive since speed is not representing actual speed.

If you’d like to have a “turnSpeed” where that value actually represents a velocity/speed over time. Use Quaternion.RotateTowards:

Pass in your ‘turnSpeed * Time.deltaTime’, and now you’re moving at that speed.

transform.rotation = Quaternion.RotateTowards(transform.rotation, rotation, turnSpeed * Time.deltaTime);
4 Likes