Quaternion Rotation - won't go past 90 degrees

Hi

What am I doing wrong here?

My transform rotates on all 3 axis but the X axis (pulling the ship’s nose up or pushing it down) stops at 90 degrees in either direction. When it reaches 90 it stops and just spins on the other axis. I thought this was fairly simple and I’m not sure where it’s going wrong. Any ideas?

Transform player;
    public float movementSpeed = 5f;
    public int invert = -1;
    float tiltSpeed = 100f;
    float rollSpeed = 300f;
    public float tiltAngle = 30f;
  

    // Start is called before the first frame update
    void Start()
    {
        player = GetComponent<Transform>();
    }

    // Update is called once per frame
    void Update()
    {
        // Get left/right/up/down
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        // Update ship position
        //transform.Translate(transform.forward * Time.deltaTime, Space.Self);

        // Update ship rotation
        Quaternion lookTowards;
        if (horizontal != 0 || vertical != 0)
        {
            float rotationX = transform.rotation.eulerAngles.x;
            float rotationY = transform.rotation.eulerAngles.y;
            float rotationZ = transform.rotation.eulerAngles.z;

            float hTurn = horizontal * tiltSpeed * Time.deltaTime;
            float vTilt = vertical * tiltSpeed * Time.deltaTime;
            float roll = horizontal * rollSpeed * Time.deltaTime;

            rotationX += vTilt;
            rotationY += hTurn;
            rotationZ -= roll;

            rotationZ = ClampAngle(rotationZ, -75, 75);
            lookTowards = Quaternion.Euler(rotationX, rotationY, rotationZ);
            transform.rotation = Quaternion.RotateTowards(transform.rotation, lookTowards, Mathf.Deg2Rad * 45f);
        } else
        {
            lookTowards = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y, 0);
            transform.rotation = Quaternion.RotateTowards(transform.rotation, lookTowards, Mathf.Deg2Rad * 45f);
        }
    }

Cheers
Dan

You’re doing individual x, y, z axis rotation calculations so you’re essentially creating your own gimbal lock problem.

Instead you can simply rotate the underlying transform in individual local space:

    void Update ()
    {
        float roll = -Input.GetAxisRaw( "Horizontal");
        float pitch = Input.GetAxisRaw( "Vertical");
        float yaw = 0;
        if (Input.GetKey( KeyCode.Alpha1)) yaw = -1;
        if (Input.GetKey( KeyCode.Alpha2)) yaw =  1;

        transform.Rotate( pitch, yaw, roll, Space.Self);
    }

Slap that on your first person camera floating in your world and use the arrow keys and 1/2 to control roll, pitch and yaw, respectively.

NOTE: the above is super-simple; I didn’t even use a speed or Time.deltaTime. You should use both.

2 Likes

I see. That works better, thanks.

I was trying to use Quaternions to avoid gimble locks. Is transform.Rotate safe from gimbal lock, or does gimbal lock just arise from trying to assign individual axis calculations?

Gimbal lock arise when you assing axis rotations one by one and one axis interflows with another. After that, you can rotate your object aroud 2 axis only instead of 3, like this


That’s essentialy the gimbal lock problem. Quaternions are build using complex numbers to avoid this problem. Transform.Rotate creates a quaternion and assigns it to the transform instance, therefore it is free from the gimbal lock.

1 Like