Setting Default Rotations

I’ve got the following code handling the rotation of a child object on the game’s player object.

private void Update()
{
    input = Mouse.current.delta.ReadValue();
}
private void LateUpdate()
{
    if (axes == RotationAxes.MouseXAndY)
    {
        vertical += input.y * sensitivityY;
        vertical = Mathf.Clamp(vertical, minimumY, maximumY);

        horizontal += input.x * sensitivityX;
        horizontal = Clamp(horizontal, minimumX, maximumX);

        if (rotateObject == null)
            transform.rotation = Quaternion.Euler(vertical, horizontal, 0.0f);
        else
        {
            //Normally vertical would be applied to the X axis, but because of the bone's orientation, we apply it to the Z axis.
            rotateObject.transform.rotation = Quaternion.Euler(0.0f, horizontal, vertical);
        }
    }
    else if (axes == RotationAxes.MouseX)
    {
        horizontal += input.x * sensitivityX;
        horizontal = Mathf.Clamp(horizontal, minimumX, maximumX);

        if (rotateObject == null)
            transform.rotation = Quaternion.Euler(0.0f, horizontal, 0.0f);
        else
            rotateObject.transform.rotation = Quaternion.Euler(0.0f, horizontal, 0.0f);
    }
    else
    {
        vertical += input.y * sensitivityY;
        vertical = Mathf.Clamp(vertical, minimumY, maximumY);

        if (rotateObject == null)
            transform.rotation = Quaternion.Euler(vertical, 0.0f, 0.0f);
        else
        {
            //Normally vertical would be applied to the X axis, but because of the bone's orientation, we apply it to the Z axis.
            rotateObject.transform.rotation = Quaternion.Euler(0.0f, 0.0f, vertical);
        }
    }
}

private float Clamp(float value, float min, float max)
{
    if (value < min || value > max)
        return 0.0f;
    else
        return value;
}

The Clamp method above is because the Mathf.Clamp method doesn’t allow the rotation to go back to 0 once a full circle is made.

Now the problem I’m having is that when the player presses the appropriate input to begin rotating this object, it automatically turns it to a weird orientation. I’m assuming this is because the default values of “vertical” and “horizontal” are 0.0f to start. Question is, how can I get the appropriate rotation values from the “rotateObject” in order to set “vertical” and “horizontal” to the correct default values (which would be whatever the values of the rotateObject’s rotation is when this script is enabled.

This isn’t generally possible due to gimbal lock.

The .eulerAngles properties you can read from a Quaternion are NOT deterministic in the sense that more than one combination of Euler angles produces identical Quaternions. When you begin doing single-axis arithmetic you will encounter different points when it gimbal-locks-out. If you are not particularly excessive in your initial rotation, you might get away with it.

If you have something with a wonky arbitrary orientation, put a parent Transform in above it that is Quaternion.identity so you can start from zeroes.

Gah… I was afraid that it was going to be an “impossible” task. Can’t put a parent on it, because it’s a bone. So I suppose my only other option is to create an empty Transform to make the bone look at, and manipulate that instead?

It’ll be fine to use the euler angles for the starting values because you’re rebuilding the rotation every frame anyways. Do it in OnEnable, Start or whatever’s appropriate.

void OnEnable()
{
   Transform target = (rotateObject == null) ? transform : rotateObject;

   horizontal = target.localEulerAngles.y;
   vertical = target.localEulerAngles.x;
}

You know, I tried doing that before but it still resulted in the default rotation being wrong. Thanks to your suggestion I went in and tried it again, and it’s still not right. However, I came up with the idea of just manually setting the default values, but setting them to an offset. This way, after the script is enabled, on the very first LateUpdate, it zeros out the rotation. Looks like this…

private void OnEnable()
{
    if (rotateObject != null)
    {
        vertical = -90.0f;
        horizontal = -90.0f;
    }
}