Search Unity

  1. Unity 2020.1 has been released.
    Dismiss Notice
  2. We are looking for feedback on the experimental Unity Safe Mode which is aiming to help you resolve compilation errors faster during project startup.
    Dismiss Notice
  3. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

[SOLVED] How to get "Rotation" value that is in the inspector?

Discussion in 'Scripting' started by AlanMattano, Mar 10, 2017.

?

Did you know that you can't Get "Rotation" value that is in the inspector?

  1. No! why not?

    78.8%
  2. Yes...

    21.2%
  1. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,098
    Except it doesn't work. The words from so many people explain why.
     
  2. ShamimAkhter

    ShamimAkhter

    Joined:
    Jun 21, 2019
    Posts:
    2
    I'm working on a flight simulator project. With this script, I can easily find the Roll/Bank, Pitch/AngleOfAttack and Yaw/Heading of my aircraft. So it's working fine. I would like to know what's the problem it's showing in your case.
     
    Deleted User likes this.
  3. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,098
    All that code does is convert eulerAngles from 0-360 into -180 to 180. That's easy, isn't the question, and there were shorter answers when this was posted.

    The Q was about how a rotation of 270 might be converted into -90 for the Inspector, or it might not. It might even be shown as 630 or -450. But a script will always see it as 270. How can a script see the same numbers as the human?
     
  4. Deleted User

    Deleted User

    Guest

    It cannot be. Unless you are using any editor extension to grab that value directly from the inspector and in that case, it won't help after the build. Personally I don't find any need for those 630 or -450 degrees values ever.
     
  5. itisieric

    itisieric

    Joined:
    Jul 15, 2018
    Posts:
    4
    This should be what you're looking for but i think you need an up to date version of unity first

    1. public float x;
    2. public float y;
    3. public float z;
    4. x = (UnityEditor.TransformUtils.GetInspectorRotation(getRotation.transform).x) + offSetX1;
    5. y = (UnityEditor.TransformUtils.GetInspectorRotation(getRotation.transform).y) + offSetY1;
    6. z = (UnityEditor.TransformUtils.GetInspectorRotation(getRotation.transform).z) + offSetZ1;
    7. Debug.Log("x: " + x);
    8. Debug.Log("y: " + y);
    9. Debug.Log("z: " + z);
     
  6. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,098
    TinyAnt suggested using TransformUtils.GetInspectorRotation a year and a half ago. The problem is it's editor-only. People are wanting this for a build (I can't figure out why -- they just want it).
     
    gameDevMode and AlanMattano like this.
  7. Cherubim79

    Cherubim79

    Joined:
    May 3, 2014
    Posts:
    55
    TL;DR: Here's some new math that works at runtime with or without the editor, I'm just explaining it, and sharing some new linear algebra finds.

    I managed to find a better solution to this, but it's a little more math heavy and I discovered some new math by trial and error along the way. I read a lot of technical whitepapers from universities, and even found along the way that you can recreate gimbal lock with Quaternions if you know what you're doing with pre or post multiplying quaternions and matrices, I'll get into that topic more in a minute.

    Here I've created an "Angular Distance" formula, which takes two Euler angles and compared by the cosines and sines of the angles.

    Code (CSharp):
    1.     float AngularDistance(Vector3 a, Vector3 b)
    2.     {
    3.         float cax, cay, caz, sax, say, saz, cbx, cby, cbz, sbx, sby, sbz;
    4.  
    5.         cax = Mathf.Cos(a.x * Mathf.Deg2Rad);
    6.         cay = Mathf.Cos(a.y * Mathf.Deg2Rad);
    7.         caz = Mathf.Cos(a.z * Mathf.Deg2Rad);
    8.         cbx = Mathf.Cos(b.x * Mathf.Deg2Rad);
    9.         cby = Mathf.Cos(b.y * Mathf.Deg2Rad);
    10.         cbz = Mathf.Cos(b.z * Mathf.Deg2Rad);
    11.         sax = Mathf.Sin(a.x * Mathf.Deg2Rad);
    12.         say = Mathf.Sin(a.y * Mathf.Deg2Rad);
    13.         saz = Mathf.Sin(a.z * Mathf.Deg2Rad);
    14.         sbx = Mathf.Sin(b.x * Mathf.Deg2Rad);
    15.         sby = Mathf.Sin(b.y * Mathf.Deg2Rad);
    16.         sbz = Mathf.Sin(b.z * Mathf.Deg2Rad);
    17.  
    18.         float ct1 = cbx - cax;
    19.         float ct2 = cby - cay;
    20.         float ct3 = cbz - caz;
    21.         float st1 = sbx - sax;
    22.         float st2 = sby - say;
    23.         float st3 = sbz - saz;
    24.  
    25.         return Mathf.Sqrt(ct1*ct1 + ct2*ct2 + ct3*ct3 + st1*st1 + st2*st2 + st3*st3);
    26.     }
    27.  
    Remember that except in the case of gimbal lock at poles where the pitch is +/- 90 degrees, you will usually retrieve two Euler angles per matrix or quaternion, which are isomorphic to each other. In the code below I obtain both angles with their respective plus or minus cosine of the pitch angle (in Unity's case the X axis) and compare to find the angle with the lowest distance, I then constrain it to within 0-360 degrees with modulo operations.

    This is a quick and simple proof of concept I coded up tonight so it doesn't have gimbal lock checking, which is fairly trivial to code, I have a better version I've been working on in ThreeJS.

    What Unity does by default is just picks the Euler angle that contains the positive cosine of the pitch angle.

    It's more efficient, but it can be very annoying if you were trying to read Euler angles that were constantly flip-flopping between positive and negative, obviously the discussion of this topic.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Rotations : MonoBehaviour
    6. {
    7.     public float Amount = 1.0f;
    8.     public bool Premultiply = true;
    9.     public Vector3 Axis = Vector3.zero;
    10.  
    11.     public Vector3 LastEuler = Vector3.zero;
    12.     public Quaternion Quat = Quaternion.identity;
    13.     public Vector3 CurrentEuler = Vector3.zero;
    14.     public Matrix4x4 M1 = Matrix4x4.identity;
    15.     public Vector3 UnityCurrentEulerChoice = Vector3.zero;
    16.  
    17.     public Vector3 AA;
    18.     public Vector3 BB;
    19.  
    20.     // Start is called before the first frame update
    21.     void Start()
    22.     {
    23.      
    24.     }
    25.  
    26.     Vector3 GetMinimumEulerDistance(Vector3 last, Vector3 a, Vector3 b)
    27.     {
    28.         float aa = AngularDistance(last, a);
    29.         float bb = AngularDistance(last, b);
    30.         Debug.Log($"{a}:{aa} - {b}:{bb}");
    31.  
    32.         if (float.IsNaN(aa))
    33.             return MakePositive(b);
    34.         if (float.IsNaN(bb))
    35.             return MakePositive(a);
    36.  
    37.         if (aa.CompareTo(bb) < 0)
    38.         {
    39.             Debug.Log("Chose A");
    40.             return MakePositive(a);
    41.         }
    42.         else
    43.         {
    44.             Debug.Log("Chose B");
    45.             return MakePositive(b);
    46.         }
    47.     }
    48.  
    49.     float AngularDistance(Vector3 a, Vector3 b)
    50.     {
    51.         float cax, cay, caz, sax, say, saz, cbx, cby, cbz, sbx, sby, sbz;
    52.  
    53.         cax = Mathf.Cos(a.x * Mathf.Deg2Rad);
    54.         cay = Mathf.Cos(a.y * Mathf.Deg2Rad);
    55.         caz = Mathf.Cos(a.z * Mathf.Deg2Rad);
    56.         cbx = Mathf.Cos(b.x * Mathf.Deg2Rad);
    57.         cby = Mathf.Cos(b.y * Mathf.Deg2Rad);
    58.         cbz = Mathf.Cos(b.z * Mathf.Deg2Rad);
    59.         sax = Mathf.Sin(a.x * Mathf.Deg2Rad);
    60.         say = Mathf.Sin(a.y * Mathf.Deg2Rad);
    61.         saz = Mathf.Sin(a.z * Mathf.Deg2Rad);
    62.         sbx = Mathf.Sin(b.x * Mathf.Deg2Rad);
    63.         sby = Mathf.Sin(b.y * Mathf.Deg2Rad);
    64.         sbz = Mathf.Sin(b.z * Mathf.Deg2Rad);
    65.  
    66.         float ct1 = cbx - cax;
    67.         float ct2 = cby - cay;
    68.         float ct3 = cbz - caz;
    69.         float st1 = sbx - sax;
    70.         float st2 = sby - say;
    71.         float st3 = sbz - saz;
    72.  
    73.         return Mathf.Sqrt(ct1*ct1 + ct2*ct2 + ct3*ct3 + st1*st1 + st2*st2 + st3*st3);
    74.     }
    75.  
    76.     Vector3 MakePositive(Vector3 input)
    77.     {
    78.         return new Vector3((360f + input.x) % 360f, (360f + input.y) % 360f, (360f + input.z) % 360f);
    79.     }
    80.  
    81.     void CalculateEuler()
    82.     {
    83.         // I'm doing this the long way computationally. Feel free to make it more efficient to your needs.
    84.         Matrix4x4 m1 = Matrix4x4.TRS(Vector3.zero, Quat, Vector3.one);
    85.         M1 = m1;
    86.         UnityCurrentEulerChoice = Quat.eulerAngles;
    87.  
    88.         // We need to convert the matrix to YXZ (see https://www.andre-gaschler.com/rotationconverter/)
    89.         float cx, cy, cz, sx, sy, sz;
    90.         float cx2, cy2, cz2, sx2, sy2, sz2;
    91.         //cy*cz+sx*sy*sz,   -cy*sz+sx*sy*cz,    cx* sy
    92.         //cx*sz,            cx*cz,              -sx
    93.         //-sy*cz+sx*cy*sz,  sy*sz+sx*cy*cz,     cx*cy
    94.  
    95.         cx = Mathf.Sqrt(m1.m10 * m1.m10 + m1.m11 * m1.m11);
    96.         cx2 = -cx;
    97.         sx = -m1.m12;
    98.         sx2 = sx;
    99.         cy = m1.m22 / cx;
    100.         cy2 = m1.m22 / cx2;
    101.         sy = m1.m02 / cx;
    102.         sy2 = m1.m02 / cx2;
    103.         cz = m1.m11 / cx;
    104.         cz2 = m1.m11 / cx2;
    105.         sz = m1.m10 / cx;
    106.         sz2 = m1.m10 / cx2;
    107.  
    108.         Vector3 a = new Vector3(Mathf.Atan2(sx, cx) * Mathf.Rad2Deg, Mathf.Atan2(sy, cy) * Mathf.Rad2Deg, Mathf.Atan2(sz, cz) * Mathf.Rad2Deg);
    109.         Vector3 b = new Vector3(Mathf.Atan2(sx2, cx2) * Mathf.Rad2Deg, Mathf.Atan2(sy2, cy2) * Mathf.Rad2Deg, Mathf.Atan2(sz2, cz2) * Mathf.Rad2Deg);
    110.         AA = a;
    111.         BB = b;
    112.         try
    113.         {
    114.             Vector3 final = GetMinimumEulerDistance(LastEuler, a, b);
    115.             LastEuler = CurrentEuler;
    116.             CurrentEuler = final;
    117.         }
    118.         catch(System.Exception ex)
    119.         {
    120.             Debug.Log($"{ex}");
    121.         }
    122.     }
    123.  
    124.     // Update is called once per frame
    125.     void Update()
    126.     {
    127.         if (Input.GetKey(KeyCode.Space))
    128.         {
    129.             Vector3 inc = Axis * Amount;
    130.             if (Premultiply)
    131.             {
    132.                 Quat = Quaternion.Euler(inc) * Quat;
    133.                 Quat = Quat.normalized;
    134.             }
    135.             else
    136.             {
    137.                 Quat *= Quaternion.Euler(inc);
    138.                 Quat = Quat.normalized;
    139.             }
    140.             CalculateEuler();
    141.         }
    142.     }
    143. }
    144.  
    Quick Note about the Code:

    Pre-multiplying a Quaternion to a rotation rotates on the world XYZ, while post-multiplying a Quaternions rotates on the object's own XYZ, changing some of its own axes potentially for each rotation when post-multiplying.

    Combining pre and post multiplying operations you can achieve gimbal lock with Quaternions wherever the pitch angle is aligned to +/- 90 degrees the roll and yaw will move in the same direction in gimbal lock. If you set the increment amount to 1.0, and pre-multiply on the X axis you'll increment by 1, while post-multiplying on the Z axis increments on 1. This is essentially similar to adding and subtracting vectors, except for the Y axis, which I've found has a pre-multiply matrix that's similar to a XYX "proper" Euler rotation and a post-multiply matrix similar to a ZYZ with the exception of some sign flips.

    Most technical whitepapers I've read on the internet don't seem to cover this and unnecessarily hype Quaternions from a lack of understanding of how pre and post multiplying work, remember that Quaternion and Matrix multiplication is isomorphic.

    Unity3D hides all this math behind interop code that's not part of the C# reference source while some gaming companies still require you to know the math behind matrices and quaternions to work for them, so it's good to know that order of axes still matters in the creation of quaternions just as much as matrices, and that you can still get gimbal lock with both despite what people on the internet hype.

    I'm in the process of building a ThreeJS educational site with interactive quaternion and matrix solvers and calculators to help you tackle all aspects of rotations interactively.
     
    loxer1337, a436t4ataf and AlanMattano like this.
  8. abdu2624

    abdu2624

    Joined:
    Aug 2, 2020
    Posts:
    1
    Here I'm trying to get the X axis

    it's quite simple, imagine 2 points on the circle one bellow the 0deg and one above it.
    Example:
    Point_Bellow = 1;
    Point_Above = 359;

    as you ca see if we want the Point_above to be as we wish we have to minus it from 360 which will make it
    Point_Above = 360 - 359 = 1;

    But you can't use the same for the Point_Bellow cuz it will just make it the same as before but just opposite
    So we have to check if the Camera.main.transform.localEulerAngles[0] which is the x angle is greater than 180
    if it is greater than 180 then the point is above the 0deg and we can use 360 - the angle otherwise you can write the angle directly or preceded by minus to make it negative

    Like this:

    if(Camera.main.transform.localEulerAngles[0] - 180 >= 1)
    {
    print(360 - Camera.main.transform.localEulerAngles[0]);
    }
    else
    {
    print(-Camera.main.transform.localEulerAngles[0]);
    }

    Another way to do it:
    Since the camera is rotated that means you are using the mouse or screen touch to rotate it, so you can from the beginning make a variable such as
    private float angel = 0;
    and change it every time you rotate the camera

    for example:
    Here is a code that check if the camera angle is inside a specific range and change it according to the mouse movement

    float y = Input.GetAxis("Mouse Y") * -1;
    if ((angel <= -45 & y > 0) || (angel >= 45 & y < 0) || (angel < 45 & angel > -45))
    {
    transform.Rotate(y, 0, 0);
    angel += y;
    }

    Hope anyone can use that, excuse my English xD as you can see I'm not a native speaker lol
     
  9. Cherubim79

    Cherubim79

    Joined:
    May 3, 2014
    Posts:
    55
    Except that localEulerAngles uses the first orientation from the Quaternion. A Quaternion or Matrix, which are isomorphic, return 2 possible orientations, unless at the poles, in which case is a singularity. Unity under the hood just uses the first one, which is ok for speed but not if you want the one closest to the original Euler angle, so at pole flips you get a different result. I’ve got code that fixes all this and gives you the closest result based on an angular distance utilizing cosine and sine and also by tracking the last Euler separately. I think I posted this already, but if not I’ll put it up on my GitHub.
     
unityunity