What is happening with Quaternions?

Hello there,

I have been trying to make a simple recoil script and I don’t understand what Unity is doing. All I want is to add a rotation upwards and slowly Lerp back to the origin rotation. Unity does some weird stuff that I don’t know why and I don’t understand why I can not simply just add rotation and why they made it so complicated with Quaternions.

This is the code:

    private float rotationDelta;

    private Quaternion startRotation;

    public void Start()
    {
        ammunition = weapon.maxAmmunition;
        startRotation = transform.rotation;
    }

    public void Update()
    {
        Quaternion qTo = Quaternion.AngleAxis(-rotationDelta, transform.forward) * startRotation;
        transform.rotation = Quaternion.Slerp(transform.rotation, qTo, Time.deltaTime * 5f);
        if(rotationDelta > 0)
        {
            rotationDelta -= 5f * Time.deltaTime;
            Mathf.Clamp(rotationDelta, 0, Mathf.Infinity);
        }
    }

In a separate Shoot method rotationDelta gets modified like that:

rotationDelta += weapon.recoilUpwards;

My gun rotates in all directions and not just one even tho I only modify using transform.forward.
Also I made a separate test by debugging like that:
Debug.Log(transform.rotation.y);
Debug.Log(transform.rotation.eulerAngles.y);

Even though y is 0 in the Unity Editor it would gave me seemingly random values as soon as I rotated the parent object. The 0 in the Unity Editor remained but the Debug.Log gave me random values.

The long answer has lots of math; the short answer is 3 dimensional Euler rotations suck even more.

Your reasoning is correct, the problem is in the implementation. All the rotations need to be relative to the parent gameobject, transform.rotation refers to the transform’s global rotation. The local rotation (relative to the parent) is accessed with transform.localRotation.

I would also recommend using Vector3.forward, as using the local axis can cause it to skew.

Here’s a modified version of your script without the wacky spinning behaviour:

    public float rotationDelta;
    private Quaternion startRotation;
    public void Start()
    {
        startRotation = transform.localRotation;
    }
    public void Update()
    {
        Quaternion qTo = Quaternion.AngleAxis(-rotationDelta, Vector3.forward) * startRotation;
        transform.localRotation = Quaternion.Slerp(transform.localRotation, qTo, Time.deltaTime * 5f);
        if (rotationDelta > 0)
        {
            rotationDelta -= 5f * Time.deltaTime;
            Mathf.Clamp(rotationDelta, 0, Mathf.Infinity);
        }
    }