Change orientation

Hi!

I was trying to change the orientation of an object on a defined axis (I tried with Y ans Z). After having a lot of trouble, I realized that my solutions were working except in the case where the said object has an initial rotation of 90 or -90 along X axis (maybe other values too).

What happened (in my script AND in the inspector) is when I changed the angle along Y or Z axis, the resulting rotation was visually the same. I have the feeling that I was falling into a specific case but I can’t put my finger on it. If you understand why it behaves that way, feel free to enlighten me :wink:

Here is the script I’m using (on a monobehaviour) :

 public void Update() // classic Unity Update 
    {       float value = (float)ControllableParameter.GetFinalValue<object>(); // the desired angle for the axis
            Vector3 currentValues = this.transform.localEulerAngles; // get current angles.
            TRACE("Desired angle : " + value + "	 current angles values : " + currentValues); // for debug purposes
            value -= (AxisToRotateAround == Axis.X ? currentValues.x :
                (AxisToRotateAround == Axis.Y ? currentValues.y : currentValues.z)
                ); // get the current angle of the selected axis and calculate the needed rotation angle to obtain the desired angle

            TRACE("rotation needs an angle of : " + value);
            
            this.transform.Rotate( AxisToRotateAround == Axis.X ? value % 360 : 0,
                                            AxisToRotateAround == Axis.Y ? value % 360 : 0,
                                            AxisToRotateAround == Axis.Z ? value % 360 : 0
                                        , Space.Self);

            TRACE("values after call to Rotate : " + this.transform.localEulerAngles);

I tried setting localEulerAngles directly instead of using Rotate (but I think it’s a bad way to do it as 2 of the angles directly depend on their current values), and various complicated ways to set this orientation.

Whatever the method, when my object has (for the case I mostly tested) a -90° angle around x axis, the modified value for the angle was modifying the Y axis instead of the Z one (I think I also had the problem where you revert Y ans Z in this sentence, but not sure) and the modification was wrong, there was an addition to the angle instead of an assignation.

Here is an example :

If my desired angle is, say, 5° around Z axis (so, getting from (-90,20,0) to (-90,20,5) I obtain the following : (-90,25,0)
But if I set angles to (-47,20,0) for example, the exact same code will produce : (-47,20.000002,5).

So my questions are :

  • do I use the correct and most efficient methods to set the angle of my object (you can think of it as what happens in Unity’s editor window, when you rotate an object to set it correctly in your scene before launching you game)?
  • If Unity’s behaviour is not abnormal, what did I miss ? (conversion to quaternions maybe ?)

Thanks

The property localEulerAngles is a decomposition of the current transform.localRotation into single rotations around the axes X, Y and Z. Since there are several combinations that may result in the same rotation, the conversion quaternion->eulerAngles isn’t reliable: it may change suddenly from one combination to another completely different (but equivalent) at certain points.

If you want to orient an object in a one-way-fashion (only your controls set the orientation, without no external factors like forces, collisions etc.), the best approach is to make currentValues a member variable set at Start and “rotate” these angles by math when needed, assigning them back to localEulerAngles - like this:

Vector3 currentValues;

public void Start(){
    currentValues = transform.localEulerAngles;
}

public void Update(){ // classic Unity Update
    float value = (float)ControllableParameter.GetFinalValue(); // the desired angle for the axis
    TRACE("Desired angle : " + value + "	 current angles values : " + currentValues); // for debug purposes
    switch (AxisToRotateAround){ // modify the desired axis:
        case Axis.X: currentValues.x = value; break;
        case Axis.Y: currentValues.y = value; break;
        case Axis.Z: currentValues.z = value; break;
    }
    transform.localEulerAngles = currentValues; // update actual object rotation
}