Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

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

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

Thread Status:
Not open for further replies.
  1. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,500
    Is there a direct way to get the value that are in the Rotation field of the inspector?
    I need that angle that is in the inspector. for example Transform > Rotation (X)

    It can be the local or world but i need the same value.
    I try :

    Code (CSharp):
    1. float angleX = myTransformGO.rotation.x;
    go from 0 to 0.5 and go down with same signe.

    Code (CSharp):
    1. float angleX = myTransformGO.rotation.eulerAngles.x;
    but the values are not the same. If i go negative go over 270 with no sign.

    So is difficult to make the math. I try variants and manual.

    Is there a direct way to get the value that are in the Rotation field of the inspector?

    Solution:

    Code (CSharp):
    1.  
    2.  
    3.     [SerializeField]
    4.     float eulerAngX;
    5.     [SerializeField]
    6.     float eulerAngY;
    7.     [SerializeField]
    8.     float eulerAngZ;
    9.  
    10.     void Update()
    11.     {
    12.         eulerAngX = transform.localEulerAngles.x;
    13.         eulerAngY = transform.localEulerAngles.y;
    14.         eulerAngZ = transform.localEulerAngles.z;
    15.    
    16.         // add the math for your need using if statemnts
    17.         // ...if ( eulerAngX  > 180f) ... code go here...[/B]
    18.  
    19.         /* Get X    [ ATT: SIMILAR TO THIS  EXAMPLE  ]
    20.  
    21.         if (  eulerAngY  > 180f)
    22.           {
    23.               if (  eulerAngX  > 256f)
    24.                   xAngle = ( eulerAngX  *-1f) +360f;
    25.               else
    26.                   xAngle= - eulerAngX;
    27.           } else {
    28.  
    29.               if (  eulerAngX  > 256f)
    30.                   xAngle=  eulerAngX  - 180f;
    31.               else
    32.                   xAngle= (( eulerAngX  * -1f) + 180f) * -1f;
    33.           }
    34. */
    35.  
    36. }
    37.  

    Could anybody write an answer about how to calculate it like Unity does?


    HERE IS A LINK TO A BEAUTIFUL MANUAL
     
    Last edited: Jan 26, 2019
    SrDidE, PastequeBuild, ow3n and 2 others like this.
  2. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,989
    No. The Inspector numbers are specially tweaked away from the code values, to look nice for humans. They depend on the starting Inspector values. Put (000) in the Inspector and run some code. Then put (360,360,-360), which is the same as 000, and run the same code. The numbers you see will be different.

    The code values you get are always 0-360. If you really want to use raw eulerAngle x,y,z, it's probably best to rely on that. Maybe if you start the Inspector at (180,180,180), you'll see the same (never tested.)

    The longer version of this is near the end of the rotations chapter in taxesforcatses-dot-com, but's it's just more examples and details.
     
  3. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,500
    I really really need the inspector values for human reasons. :oops: [VOTE HERE]
    I wish that "transform.Rotation" returns the values is in the inspector. With capital "R".

    upload_2017-3-10_17-46-33.png
     
    Last edited: Mar 12, 2017
    vonSchlank and bon1254 like this.
  4. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    916
    transform.rotation.x is a complex number. its not a angle and oscillates from -1 to 1. same goes for y,z,and w components
    as for converting to +/- 180:
    Code (CSharp):
    1.  
    2.         private static float WrapAngle(float angle)
    3.         {
    4.             angle%=360;
    5.             if(angle >180)
    6.                 return angle - 360;
    7.  
    8.             return angle;
    9.         }
    10.  
    11.         private static float UnwrapAngle(float angle)
    12.         {
    13.             if(angle >=0)
    14.                 return angle;
    15.  
    16.             angle = -angle%360;
    17.  
    18.             return 360-angle;
    19.         }
    so WrapAngle will convert 270 to -90
     
    DatDzua, Rioneer, oAzuehT and 25 others like this.
  5. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,500
    So how do I use this 2 functions? I pass them the "transform.rotation.x" oscillation or the Euler angle?
     
  6. joshuaflash

    joshuaflash

    Joined:
    Oct 27, 2015
    Posts:
    36
    Your best bet is probably writing your own Rotations script using [SerlializeField] with private variables that read the eulerAgles. Update the values using [ExecuteInEditMode] and you will be able to see the corresponding values in the inspector on your Rotations script. They won't be the same as the values seen in transform, but they should satisfy your human reasons ;-)

    https://docs.unity3d.com/ScriptReference/ExecuteInEditMode.html
     
    elngarsamy96 and AlanMattano like this.
  7. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,500
    You mean by accuracy? In any case I need the value for my game. I'm not an expert but if i use [ExecuteInEditMode] It will be included into the build?
     
  8. joshuaflash

    joshuaflash

    Joined:
    Oct 27, 2015
    Posts:
    36
    upload_2017-3-11_16-36-39.png

    Sort of like this. They might differ by 360, but you can see them update. If you just use these instead of the values shown in the transform component, you can manipulate them for your game using only the localEulerAngles.

    Code (CSharp):
    1. [ExecuteInEditMode]
    2. public class EnableDTScript : MonoBehaviour {
    3.  
    4.  
    5.     [SerializeField]
    6.     float eulerAngX;
    7.     [SerializeField]
    8.     float eulerAngY;
    9.     [SerializeField]
    10.     float eulerAngZ;
    11.  
    12.  
    13.     void Update() {
    14.  
    15.         eulerAngX = transform.localEulerAngles.x;
    16.         eulerAngY = transform.localEulerAngles.y;
    17.         eulerAngZ = transform.localEulerAngles.z;
    18.  
    19.     }
    20. }
     
  9. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,500
    I do not need to manipulate them. Yes I had multiple manipulations of them. And at the end, I need the angle of incidence that is exactly what is in the inspector!
    But looks like there is no direct way to GET the inspector value. After you make a lot of manipulations to an object (for example using look at) the object quaternion has arbitrary orientation. In the case that arbitrary orientation is fix , then is possible to get the angles by using if statement for each quarter of the 360. And making same math to each value you get the value that is in the inspector. What bothers me is that I can look to the value that is ready for me in the inspector but I'm not able to use it in any way. [FEEDBACK VOTE LINK]
     
    Last edited: Mar 11, 2017
  10. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,454
    Look, rotations are handled by Quaternions. If you're doing anything with rotations you need to be familiar with at least Quaternion.Euler(Vector3 input) and the fact that the inspector values are just an euler version of the Quaterion that is in reality the real rotation value of some object. There are many euler ways to represent the same exact Quaternion value, so you can have stuff like (0,0,0) also perfectly equal to (360,-360,-360). That applies to eulers as well, but Quats of course hit more niche values and hopefully you see the point.

    You can basically get anything you want in euler values by doing Quaterion.Euler(). If you want to manipulate rotations with euler values, do it with Quaterion.Euler(). If you want to use Euler values, manipulate the rotation of a transform with Quaternion.Euler().

    Don't get your hopes up. You're asking for something that on a technical level is a non-issue because a little understanding of the context reveals that you can easily use the currently exposed values to accomplish what you're asking.
     
    Last edited: Mar 11, 2017
    Olipool and AlanMattano like this.
  11. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    916
    I don't know what everyone keeps talking about. The fact that multiple angles can represent the same Quaternion doesn't matter, its moot and irrelevant to the OP. which angles that get represented in a Vector3 depends on the rotation order specified. and pretty much everything in unity defaults to the same rotation order, the Transform inspector included. and this is why that fact is irrelevant.

    The Transform inspector is simply displaying the local euler angles in the order of ZXY. transform.localEulerAngles will return the same values. This is because ZXY is the default order in Unity for any rotation represented as a Vector3. This includes transform.eulerangles, transform.Rotate (which mentions this in its documentation), and Quaternion.eulerAngles.

    Alan just wants to read out the same angles that the inspector displays. He doesn't have to worry about gimble lock or any special properties revolving around Quaternions. Just use transform.localEulerAngles and be done with it.

    as said before. transform.rotation is a Quaternion and the Quaternion components (x,y,z,w) are NOT angles they are complex numbers. unless you understand the math behind Quaterions leave these variables alone. Now Quaternions isn't rocket science, its just an expansion of high school math. Remember imaginary numbers (square root of -1)? Quaternions is just the 3D version of imaginary numbers.Simply put they are not the variables you want.

    you will want to use UnwrapAngle(transform.localEulerAngles.x); You'll get an angle of x that ranges from -180 to +180.
     
    precipice, Slycodger, zeiksz and 8 others like this.
  12. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,989
    The problem is it doesn't -- eulerAngles and what the Inspector shows are not the same. Of course, they're the same angle, but not the same numbers.

    The Inspector saves your original hand-entered values. Then it takes the real eulerAngles and adjusts them to keep the Inspector as close to those starting values as possible -- using either +/-360 or flipping x (the "over the top" problem.) You can see this -- enter 1234 into an Inspector rotation slot. Then run `transform.rotation=Quaternion.identity;`. It will snap to 1080, which is the closest multiple of 360 to your starting 1234.

    That's why the Inspector seems to prefer -180 to 180, since most slots usually start at 0. But if a slot starts at 180, suddenly Unity prefers 0-360 for that one slot.
     
  13. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,500
    Thx @Owen-Reynolds for your Re numbers ;) --> Vector and Rotation link . Good place to start.

    Thanks All for the great support!

    At the end I finish making the all the math for getting what is in the inspector field. My script is different because the GameObject starting rotation is different from 000 (identity). I think my starting rotation is -90 in Y. Here is the script

    Code (CSharp):
    1.  
    2. // drag and drop in the inspector game object to look at
    3. public Transform myGameObjectTransform;
    4. public float xAngle; // the result value in angles
    5.  
    6. void FixedUpdate()
    7.     {
    8.         // Get X
    9.         if (myGameObjectTransform.eulerAngles.y > 180f)
    10.         {
    11.             if (dragAlphaArrow.eulerAngles.x > 256f)
    12.                 xAngle = (myGameObjectTransform.eulerAngles.x *-1f) +360f;
    13.             else
    14.                 xAngle= -myGameObjectTransform.eulerAngles.x;
    15.         } else {
    16.  
    17.             if (myGameObjectTransform.eulerAngles.x > 256f)
    18.                 xAngle= myGameObjectTransform.eulerAngles.x  - 180f;
    19.             else
    20.                 xAngle= ((myGameObjectTransform.eulerAngles.x * -1f) + 180f) * -1f;
    21.         }
    22. }
    I repeat: My starting rotation is -90 in Y. So that is the reason I put strange arbitrary values as for example 256. And is working correctly. I'm open to critics.

    I'm an artist, not a coder or an engineer. If you want to check values for debugging I suggest strongly to make something like this, to double check what you are doing.
     
    Last edited: Mar 12, 2017
    maurizio55 likes this.
  14. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,500
  15. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,500
    @Eric5h5 Thanks for your comment. I take my time to understand the problem before answering to you. I disagree with your comment.

    Because is not just "Transform.eulerAngles" but the values are not the same. If i go negative go over 270 with no sign. And you get positive numbers with no sign, so you need to compare with another point, etc. Also you need to find that in the documentation and since there are a lot of rotation functions it takes time to understand there is no direct way to get the value.

    And as an artist looking the inspector the result bothers me that I can´t just use that value that is in there all the time as I do for example for position , scale or other UI transform variables.


    Yes probably using Transform > Rotation (X) (with capital R) is a bad idea and creates confusion. But i wish that value to be accessible. Probably there is a better way to call it. Because is not coherent with other components way of getting values. But with a more appropriate name consistent with the inspector can be more useful for dose as me that do want exactly the same value the is in the inspector without losing too much time.

    Code (CSharp):
    1. float AOA = myAirplaneTransform.eulerInspectorAngle.x;
    or

    Code (CSharp):
    1. float AOA = myAirplaneTransform.getInspectorRotation.x;
    or a more intelligent way. But Eric, I wish it as a further because I need it. Actually, in my game, I use it in approximately 100 different game-objects.
     
    vonSchlank likes this.
  16. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    The inspector values don't exist in anything other than a temporary form used only for display. What is stored on the transform is Transform.rotation, nothing else. You can use Transform.eulerAngles (same as the inspector) to display the rotation in a more familiar form than quaternions. You may have missed this part: "You can temporarily make rotation values like -90, however toggling play mode will reset them to the actual values that you get from Transform.eulerAngles." You can't have a "eulerInspectorAngle" because it doesn't really exist.

    --Eric
     
  17. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    I don't really understand this insistence that you need to get the inspector's values in code. If a certain rotation is mathematically represented by several solutions, then that's just the nature of math. As far as human readability goes, 0 and 360 are both human readable, but mathematically speaking the end result is the same.

    Also let's not forget that the inspector is a dev tool. Whatever values are in there are irrelevant to the end user since they'll never see it. I'm not sure placing this kind of requirement on the inspector makes sense.

    Let's say that even if you do get the inspector values in the code. Now what? You still can't reliably output to the inspector from code. The inspector is just representing a quaternion.

    Someone also pointed out that if you absolutely positively must have values matching between the inspector and code, then you're going to have to do that yourself using a custom drawer.
     
  18. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,500
    If you need to get inspector's values in code, then you need the code I posted earlier. But even that is not enough. You just get only a quarter of the sphere. I was not able to get the other three-quarters. Is not as simple as it appears or my skills are limited.

    At the moment using quaternions is out of my comprehension.
     
    Last edited: Sep 2, 2017
  19. tinyant

    tinyant

    Joined:
    Aug 28, 2015
    Posts:
    127
    I think you should use C# reflection to get the transform inspector rotation value.
    it's just a Vector3Field for temp vector3 value.
    so you should get your selected GameObject and get the TransformInspector instance and to get the Temp field (Vector3) in the TransformInspector.
     
    DDeathlonger and AlanMattano like this.
  20. tinyant

    tinyant

    Joined:
    Aug 28, 2015
    Posts:
    127
    Code (CSharp):
    1.             Vector3 vect3 = Vector3.zero;
    2.             MethodInfo mth = typeof(Transform).GetMethod("GetLocalEulerAngles", BindingFlags.Instance | BindingFlags.NonPublic);
    3.             PropertyInfo pi = typeof(Transform).GetProperty("rotationOrder", BindingFlags.Instance | BindingFlags.NonPublic);
    4.             object rotationOrder = null;
    5.             if (pi != null)
    6.             {
    7.                 rotationOrder = pi.GetValue(targetTrs, null);
    8.             }
    9.             if (mth != null)
    10.             {
    11.                 object retVector3 = mth.Invoke(targetTrs, new object[] { rotationOrder });
    12.                 vect3 = (Vector3)retVector3;
    13.                 Debug.Log("Get Inspector Euler:" + vect3);
    14.             }
    Try this.
    Unity3d Use internal GetLocalEulerAngles method to get the tmp vector3 value in TransformInspector.
     
  21. NathanVanHouten

    NathanVanHouten

    Joined:
    Sep 6, 2012
    Posts:
    1
    For each value in transform.eulerAngles or transform.localEulerAngles if it is a child,

    if (value >= 270)
    value -= 360;
     
  22. Baumkuchen

    Baumkuchen

    Joined:
    Feb 14, 2016
    Posts:
    8
    Is there no other way to get the EulerAngle? Unity calculate it by its own.... so could anybody write a post how to calculate it like Unity does^^.
     
    AlanMattano likes this.
  23. Janoschii

    Janoschii

    Joined:
    Oct 15, 2014
    Posts:
    9
    @AlanMattano The script solved this problem for me and RectTransform. You need than to ignore the rotation values of the RectTransform Component in the inspector and only work with the values of the RectTransformRotator component. I can now set any value and also animate to any value. No matter if they are more than 360° or less than 0°. I use the asset Advanced Inspector so I could easily expose properties. You would need to build a own custom inspector to expose the properties or buy Advanced Inspector.


    using AdvancedInspector;
    using UnityEngine;

    namespace Lib.Jesko.Helper
    {
    [ExecuteInEditMode]
    [AdvancedInspector(true,false)]
    public class RectTransformRotator : MonoBehaviour
    {
    void Awake() { if( rt == null ) rt = GetComponent<RectTransform>(); }
    void OnValidate() { if( rt == null ) rt = GetComponent<RectTransform>(); }

    [SerializeField, HideInInspector] RectTransform rt;

    [SerializeField, HideInInspector] float _lx;
    [SerializeField, HideInInspector] float _ly;
    [SerializeField, HideInInspector] float _lz;

    [Inspect] public float localX { get { return _lx; } set { _lx = value; rt.localEulerAngles = new Vector3(_lx,_ly,_lz); } }
    [Inspect] public float localY { get { return _ly; } set { _ly = value; rt.localEulerAngles = new Vector3(_lx,_ly,_lz); } }
    [Inspect] public float localZ { get { return _lz; } set { _lz = value; rt.localEulerAngles = new Vector3(_lx,_ly,_lz); } }
    [Inspect] public Vector3 localRotation { get { return new Vector3(_lx,_ly,_lz); } set { _lx = value.x; _ly = value.y; _lz = value.z; rt.localEulerAngles = new Vector3(_lx,_ly,_lz); } }
    }
    }


     
    Last edited: Mar 2, 2018
    ModLunar and AlanMattano like this.
  24. tinyant

    tinyant

    Joined:
    Aug 28, 2015
    Posts:
    127
    In Unity2018 U can just call UnityEditor.TransformUtils.GetInspectorRotation(transform); to get inspector values.:)
     
  25. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,989
    A note: like the accepted solution just above, TansformUtils is editor only. I feel like people wanting this are wanting to use the values during a real game, for example directly checking eulerAngles.z>45 without having to worry about it having a different value outside of the Inspector.
     
  26. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,500
    SUPER AWESOME!

    Agree completely. But can be useful to start understanding how rotation works in Unity C#
    Hi, @Adam-Buckner I know that you have done this before but >
    I feel now what is missing from Unity is a big nice live tutorial only about the rotation.
    • Using Physics force
    • Force needed and C# interaction.


    • Without using physics using C#
    • Difference between Rotate and Rotation
      > Rotate: adding rotation angles to the actual rotation? spin
      > Rotation: rotate to a final fixed direction angle using the global world space? fix

    • How to Set Globally the game object
      > to a fix rotation in world space.
      > and make spin it in world space adding angles.
    • How to Set Locally the game object
      > to a fix rotation
      > and make it spin it local space.

    • How to Get Globally the game object
      > the fix rotation in world space
      > and get the spin difference.
    • How to Get Local
      > fix rotation
      > and the spin difference.
    The pre-recorded live tutorials are also awesome!
     
    Last edited: May 16, 2018
    Mikhail94, DDeathlonger and tinyant like this.
  27. ClayBudin

    ClayBudin

    Joined:
    May 10, 2017
    Posts:
    6
    Just to chime in here. I understand that there are multiple Euler Angle representations of
    any given Quaternion, but I do think it strange the way Unity does the conversion. If I have
    a script which has:

    gameObj.transform.rotation = Quaternion.identity;


    and I run it on an object, that object's Rotation values in the Inspector sometimes show up
    as 0,0,0, but sometime they also come up as 0,-360,0 or even -180,-180,-180. I understand
    that these are equivalent, but certainly the Identity Quaternion should always translate to
    0,0,0 shouldn't it?

    Clay Budin
    NYC
     
  28. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,989
    The Inspector tries to use values as close as possible to how it started. The idea is, suppose you start Inspector y at -270 and have it naturally spin. In the Inspector, you'll see -269, -268 ... looks very nice. But for real, in the program, y was converted to a "canonical" value of 90. Run the same program with y starting at 450 and in the program it will still convert to 90. But now the Inspector shows it going 451, 452 ... .

    I wrote this a different way in some posts back in the thread.
     
  29. ClayBudin

    ClayBudin

    Joined:
    May 10, 2017
    Posts:
    6
    Interesting. And I guess that makes sense, from one point for view at least.

    I'm writing a simple tool to clear transforms and it would be good for the user
    if clearing the rotation set it to 0 0 0, rather than something else that might
    be equivalent but doesn't immediately look like it.

    Has anyone done this before? Is the answer to "ramp down" the rotations
    gradually from whatever values they are to 0 0 0 so the Inspector represents
    it that way?

    Thanks,
    Clay Budin
    NYC
     
    AlanMattano likes this.
  30. AAAAAAAAAE

    AAAAAAAAAE

    Joined:
    Jun 8, 2013
    Posts:
    100
    You are a life saver!
     
  31. curtiswer_unity

    curtiswer_unity

    Joined:
    Oct 1, 2018
    Posts:
    1
    So if there is a parent you can just do Vector3.Angle(transform.parent.up, transform.forward) - 90. This will return the value in the inspector for X, and can be easily modified for Y and Z (Using transform.parent.forward and transform.parent.right). If there isn't a parent you can use Vector3.up.
    You can't use this to set the value, but with Rotate you should figure it out.
    To clarify you can't use tranform.up for the child, as that wouldn't distinguish up from down
    Similarly, Vector3.Angle(transform.parent.forward, transform.forward) won't work properly.

    An example of me using this to clamp a GameObject named Sphere's x rotation to -12, while trying to aim the object at a target GameObject.
    bool Aim()
    {
    Sphere.transform.rotation = Quaternion.LookRotation(Vector3.RotateTowards(Sphere.transform.forward, target.transform.position-Sphere.transform.position, TurnSpeed*Time.deltaTime, 0.0f));
    float angle = Vector3.Angle(transform.up, Sphere.transform.forward);
    if (angle > 102)
    {
    Sphere.transform.localEulerAngles = Sphere.transform.localEulerAngles[0] < 0
    ? new Vector3(-12, Sphere.transform.localEulerAngles[1], Sphere.transform.localEulerAngles[2])
    : new Vector3(12, Sphere.transform.localEulerAngles[1], Sphere.transform.localEulerAngles[2]);
    return false;
    }
    return true;
    }
     
    Last edited: Oct 12, 2018
  32. Cherubim79

    Cherubim79

    Joined:
    May 3, 2014
    Posts:
    56
    I've looked at this thread and have done the math, and am still wondering about a way to get the original Inspector View's Euler Angles in the scene at runtime, not to use them in a game actually. I googled for UnwrapAngle and found it on a page, which looks like it only handles the 360 condition. When I bring an X value past 90 degrees it makes the Y and Z 180 degrees, and starts to subtract from X until I bring X to 270 degrees in the Inspector.

    As a simple test, I tried putting both the UnityEditor.TransformUtils.GetInspectorRotation vector, which understandably only works in the editor, and the transform.localEulerAngles converted over to a Quaternion, and the Quaternions are different as I see.

    I also tried implementing an Euler to Quaternion formula I found on Wikipedia, which had different results in terms of numbers from Unity's implementation, both on the inspector angles and localEulerAngles.

    I'm only interested in the math that converts between Euler Angles and Quaternions in Unity so that I can understand them, as well as the method by which Unity changes Euler angles. My interest is mostly in understanding Quaternions for gaming, mathematical, and scientific purposes. I simply want to understand the conversion math involved, which seems to create a lot of confusion if you want to understand it. Seems like a rational and reasonable request, especially since it looks like the transform's local to world matrix is read only.

    EDIT: Looks like I found a workaround. I built a Rotation MonoBehavior that stores a Vector3, Quaternion, and Transform, on its Update() function I set Q = Quaternion.Euler(V); T.localRotation = Q; where V is my originating Vector3, and it works as a pass-through component, changing V rather than the object's rotation directly. You obviously wouldn't want to do this ubiquitously throughout Unity, but if you're trying to understand how Quaternions work, it can help you gain some insight. I had a gaming company that I tried to apply for once that asked me during an interview questionnaire and test if I knew Quaternions and Transform Matrices. So I set out to want to understand them. It sounds kind of like an unreasonable question for an interview related to Unity3D programming, considering that Quaternions are hidden behind the scenes in Unity, you would never want to change them directly, neither are you able to change the transform matrices for a Transform. I'd say that God saved me from working for them since they're asking questions they might not even know.
     
    Last edited: Nov 24, 2018
  33. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,500
    I really think you need to build something like this visual helper (down here) because is not so simple to understand in local space the result when you make just the math. Unfortunately, I do not have time to look for the code. But is time let me I will try to put here the cs code.

     
  34. Cherubim79

    Cherubim79

    Joined:
    May 3, 2014
    Posts:
    56
    I built my own actually and figured out some interesting things about Quaternions.

    Firstly, order matters at EVERY step in the process. The exercise was to figure out if I could get a 1 to 1 conversion from Euler to Quaternion and back. I'm posting this to help developers who may be scratching their heads over this one.

    Firstly, most of the information you see on Euclideanspace and Wikipedia is wrong for Unity, why? Simple, order matters. The ones on those sites assume XYZ order, you have to build your conversion function from Euler to Quaternion in YXZ order to match what the editor says, that means:

    q.w = sy*sx*sz+cy*cx*cz
    q.x = cy*sx*cz+sy*cx*sz
    q.y = sy*cx*cz-cy*sx*sz
    q.z = cy*cx*sz-sy*sx*cz

    Where sx = Sine(X/2) and cx = Cosine(X/2), cy/sy for Y/2, and cz/sz for Z.

    Some code:

    double x = ((double)euler.x) / 360.0 * 2.0 * Math.PI;
    double y = ((double)euler.y) / 360.0 * 2.0 * Math.PI;
    double z = ((double)euler.z) / 360.0 * 2.0 * Math.PI;

    // Abbreviations for the various angular functions
    double cx = Math.Cos(x * 0.5);
    double sx = Math.Sin(x * 0.5);
    double cy = Math.Cos(y * 0.5);
    double sy = Math.Sin(y * 0.5);
    double cz = Math.Cos(z * 0.5);
    double sz = Math.Sin(z * 0.5);
    Vector4 xSandwich = new Vector4((float)sx, 0f, 0f, (float)cx);
    Vector4 ySandwich = new Vector4(0f, (float)sy, 0f, (float)cy);
    Vector4 zSandwich = new Vector4(0f, 0f, (float)sz, (float)cz);
    Quaternion q5 = CreateVectorSandwich(ySandwich, xSandwich, zSandwich);



    public static Vector4 SandwichProduct(Vector4 q1, Vector4 q2)
    {
    Vector4 q;
    q.w = -q1.x * q2.x - q1.y * q2.y - q1.z * q2.z + q1.w * q2.w;
    q.x = q1.x * q2.w + q1.y * q2.z - q1.z * q2.y + q1.w * q2.x;
    q.y = -q1.x * q2.z + q1.y * q2.w + q1.z * q2.x + q1.w * q2.y;
    q.z = q1.x * q2.y - q1.y * q2.x + q1.z * q2.w + q1.w * q2.z;
    return q;
    }

    public static Quaternion CreateVectorSandwich(Vector4 a, Vector4 b, Vector4 c)
    {
    Vector4 v = SandwichProduct(SandwichProduct(a, b), c);
    Quaternion q = new Quaternion(v.x, v.y, v.z, v.w);
    return q;
    }


    Next, despite all of the public information that treats Quaternions like some esoteric transcendental magic when it comes to the matrix of rotation, it's not. Order matters there too, which makes me question a lot of things about Quaternions even more, they're definitely not as great as people try to hype them up to be, but the one thing they do well is apply a combined rotation, which is needed to get around the Gimbal Lock problem, although, I've read some forum posts of people having Gimbal Lock issues with Quaternions, though I haven't seen such a problem manifest. Euclideanspace briefly mentions some issues they had with discrepancies between them and NASA standards.

    Anyway, in order to reconstruct the Rotation Matrix properly, you need to swap out how you treat X, Y, and Z in your matrix when you construct it. I built all 36 permutations through code like so:


    public double[,] CreateRotationMatrixFromQuaternion(double first, double second, double third, double w)
    {
    double[,] matrix = new double[3, 3];
    double x = first;
    double y = second;
    double z = third;
    double m1_1 = 1.0 - 2.0 * (y * y + z * z);
    double m1_2 = 2.0 * (x * y - z * w);
    double m1_3 = 2.0 * (x * z + y * w);

    double m2_1 = 2.0 * (x * y + z * w);
    double m2_2 = 1.0 - 2.0 * (x * x + z * z);
    double m2_3 = 2.0 * (y * z - x * w);

    double m3_1 = 2.0 * (x * z - y * w);
    double m3_2 = 2.0 * (y * z + x * w);
    double m3_3 = 1.0 - 2.0 * (x * x + y * y);
    matrix[0, 0] = m1_1; matrix[0, 1] = m1_2; matrix[0, 2] = m1_3;
    matrix[1, 0] = m2_1; matrix[1, 1] = m2_2; matrix[1, 2] = m3_3;
    matrix[2, 0] = m3_1; matrix[2, 1] = m3_2; matrix[2, 2] = m3_3;
    return matrix;
    }

    public double[] CreateEulerFromRotationMatrix(double[,] matrix, int idx1, int idx2, int idx3)
    {
    double[] angles = new double[3];
    double ftany = matrix[2,1];
    double ftanx = matrix[2,2];
    double first = System.Math.Atan2(ftany, ftanx);
    double stany = matrix[1,0];
    double stanx = matrix[0,0];
    double second = System.Math.Atan2(stany, stanx);
    double tsiny = matrix[2, 0];
    double third = System.Math.Asin(-1.0 * tsiny);
    angles[idx1] = first;
    angles[idx2] = second;
    angles[idx3] = third;
    return angles;
    }

    public List<double[]> GetAllEulerAngles(NewQuaternion q)
    {
    List<double[,]> matrices = new List<double[,]>();
    List<double[]> angles = new List<double[]>();
    matrices.Add(CreateRotationMatrixFromQuaternion(q.x, q.y, q.z, q.w));
    matrices.Add(CreateRotationMatrixFromQuaternion(q.x, q.z, q.y, q.w));
    matrices.Add(CreateRotationMatrixFromQuaternion(q.y, q.x, q.y, q.w));
    matrices.Add(CreateRotationMatrixFromQuaternion(q.y, q.y, q.x, q.w));
    matrices.Add(CreateRotationMatrixFromQuaternion(q.z, q.x, q.y, q.w));
    matrices.Add(CreateRotationMatrixFromQuaternion(q.z, q.y, q.x, q.w));
    for (int i1=0;i1<6;i1++)
    {
    angles.Add(CreateEulerFromRotationMatrix(matrices[i1], 0, 1, 2));
    angles.Add(CreateEulerFromRotationMatrix(matrices[i1], 0, 2, 1));
    angles.Add(CreateEulerFromRotationMatrix(matrices[i1], 1, 0, 2));
    angles.Add(CreateEulerFromRotationMatrix(matrices[i1], 1, 2, 0));
    angles.Add(CreateEulerFromRotationMatrix(matrices[i1], 2, 0, 1));
    angles.Add(CreateEulerFromRotationMatrix(matrices[i1], 2, 1, 0));
    }
    return angles;
    }


    Then I could test in the editor by rotating against a copy of an object that I sent the Euler angles to. The one that worked was index 29, which should have a matrix created in ZXY order in CreateRotationMatrixFromQuaternion, and the variables are pulled back in ZYX order, with Z being the one that's pulled first by Arcsine. It's the only permutation which doesn't suffer any weird flipping problems when recreated.

    So to recap, create your Euler to Quaternion function in YXZ order, not simply switching around variables but create the function by the sandwich (V_out=q*V_in*q^-1) products of (Y*X)*Z and put your variables in XYZ (q.x = x, q.y = y, q.z = z, q.w = w). Then on pulling them from Quaternion to Euler create your rotation matrix in ZXY order and pull your variables out in reverse ZYX.

    By the way, in defense of the Unity fellows, the actual Arcsine, Arccosine, and Arctangent functions themselves are at the root of why an X angle of say 91 degrees Euler will have a Y and Z of 180 if both Y & Z were 0.

    I'm looking through this article now and wondering if I can pull back 2 different Euler Angles for every pull, and see if I can simply pick the best one based on some factors for how "pretty" I want to make the output essentially:

    https://drive.google.com/file/d/0B9rLLz1XQKmaUHhmMExJbVZtb0U/view

    I'll update if that goes well.

    Really makes me think of Cosine and Sine problems on the whole though and rotation systems in computers. I've been mucking around some hypotheses in my head on how to achieve a better rotational system by retaining original quadrant information of Cosines and Sines, the problem is it doesn't look like it's commutative. Could potentially help with the spectral leakage problem in DSP with Fourier Transforms. I dated a gal once, prettiest gal I ever met, her father worked at NASA for Mission Control when he was alive, so I know he knew all about Quaternions and DSP, he was a radio communications expert, engineer, and chemist. She laughed at me when I mentioned Quaternions, and you know what? She's right. I don't wanna go all Sir William Rowan Hamilton here, but I just feel in my gut like there's a better solution to be had for rotations in general, it's been boiling in my mind, just ported some code over from R to C# in Unity for Fourier smoothing of any arbitrary time-series data like stock market data for example, and I noticed the ends of the spectrum have a singularity problem the more you smooth them, and I've been wondering about a potential solution. Just thinking out loud. Cheers.
     
    Last edited: Dec 4, 2018
  35. Cherubim79

    Cherubim79

    Joined:
    May 3, 2014
    Posts:
    56
    It looks like the inverse angle fixes it where X is between 90 and 270 degrees. You take Pi minus the arcsine calculated angle and use its cosine in the arctangent conversion to get an inverted angle as per this paper:

    https://drive.google.com/file/d/0B9rLLz1XQKmaUHhmMExJbVZtb0U/view

    I also show it on the left in the screenshot.

    The trouble though comes down to "which Euler is the best pick." Both angles describe the same rotation, however, one is the original notation and one isn't. You could say, "pick the one of the two with the highest X angle", but there are some weird unknowns when you have say {x = 109, y = 181.7, z = 267.1} in the inspector (you can also see that I built a whole rotation class for this for testing purposes). The returned values the regular Unity way are: {x = 71, y = 1.7, z = 87.1} while the inverse angle is {x = 109, y = -178.3, z = -92.9}, which, if clamped within 0-360, is the same as the inspector on the second one, even though it has negative values in it, which works, but means I can't use negatives in the determination of which angle to choose exactly. Things get the trickiest where X is between 180 and 270 it looks like, because a little over X=180 and you have X values on the inverse close to 360, even though the higher is not the right one, until you get past 270. So, given the clamped values, that gives you essentially 4 rotations to choose from, all doing the same thing but represented differently.

    So you might have some conditional logic to say choose the highest X unless both are > 180, then do something else, that something else is what I'm figuring out. It's a brain teaser, a real Tower of Hanoi puzzle from the depths of hell, my hats off to the Unity engineers. Actually, ding, ideas.

    I'll update when I have more progress on it, it looks like in many scenarios I can get right back to inspector values, but there are a few outliers that get tricky. It's an improvement nonetheless, and I think I may just about have it licked.

    EulerTest.png

    ***UPDATE***: I've got the problem licked, about as much as perhaps can be, I just need to clean up the code. Ok, so the fix for the problem is what I call Pitch Isolation. You create a new rotation matrix using only the pitch value, in Unity's case the X actually, which is the one obtained by Arcsine rather than Arctangent. On its own rotation matrix with only the pitch value as the Quaternion, you can get one of the two Euler angles representing the Quaternion and apply some rules to it to basically fish a Quaternion out of a Black Hole.

    However, I just want the Unity team to think about this for a moment if you haven't already. You've got these Euler angles, which convert over to Quaternions, you lose data by going to a Quaternion, because what is a Quaternion? It's a collection of Sines and Cosines which ignores the originating quadrant information. You can, however, programmatically go through the steps to take an Euler angle, feed it into the variables you would in a Quaternion to create its rotation matrix directly, which essentially SOLVES THE PROBLEM of gimbal lock, if you collect data about both systems in the breadcrumb trail. Ask yourself the mathematical question, why does gimbal lock occur in the first place? Well, it has to do with the dependency chain of rotations, a degree of freedom is lost because in the original orthogonal matrix implementations for rotations of Euler angles it doesn't take into account numbers which account for all 3 angles at once, Quaternions do. So, what I'm saying is, by combining the systems rather than separating them, into one Rotation class, which takes the Euler angle and produces the same rotational matrix as a Quaternion, now you don't lose data about the quadrant that the original angles are in, in fact, you have the original data retained. I'm going to test and see if by cutting the middle man and creating one combined rotational system if it gets around the need for things like Slerp and LookAt in Quaternions. How? Track the angles but don't actually use them as Euler angles, instead pass them off into created Quaternions. It would be wonderful if Unity would allow setting the rotational matrix directly, but I'll see how far I can go with combining, which is basically in a way to an extent what the Quaternion does anyway by allowing you to multiply by Quaternion.Euler created angles, I'm just connecting some pieces together and testing them to see where it goes and what problems I may run into.
     
    Last edited: Dec 5, 2018
    AlanMattano likes this.
  36. The-any-Key

    The-any-Key

    Joined:
    Jan 19, 2019
    Posts:
    7
    @GuardianArchangelJohn
    I combined your solution to get the Unity inspectors Euler angle "type" at index 29. And added a 360 over step detector. Every time: last_euler-(current_euler_index19_value+(360*euler_x_360_pass)) is above or below 180 (when it flip sign) I increase or decrease euler_x_360_pass. This however gives me a limitation that I can not rotate above 180 in one tick/update. But I just want to collect the rotations from animations so this is ok for me.
    EulerGetUnity.png

    Code in update:
    Code (CSharp):
    1.  
    2. // Get current euler list
    3. Euler_list = GetAllEulerAngles();
    4. // Get Unity Euler
    5. double[] value = Euler_list[29];
    6. double EulerX_org = Mathf.Rad2Deg * value[0];
    7. double EulerY_org = Mathf.Rad2Deg * value[1];
    8. double EulerZ_org = Mathf.Rad2Deg * value[2];
    9.  
    10. // Add 360 passes
    11. EulerX = EulerX_org+(360 * euler_x_360_pass);
    12. EulerY = EulerY_org+(360 * euler_y_360_pass);
    13. EulerZ = EulerZ_org+(360 * euler_z_360_pass);
    14.  
    15. // Check if x passed 360
    16. float x_change = (float)last_euler_x - (float)EulerX;
    17. if (Mathf.Abs(x_change) >180)
    18. {
    19.     // Passed 360
    20.     // Check direction we passed
    21.     if (x_change>0)
    22.     {
    23.         // Add 360
    24.         euler_x_360_pass += 1;
    25.     }
    26.     else
    27.     {
    28.         // Sub 360
    29.         euler_x_360_pass -= 1;
    30.     }
    31.     // Recalc euler
    32.     EulerX = EulerX_org + (360 * euler_x_360_pass);
    33. }
    34.  
    35. // Check if y passed 360
    36. float y_change = (float)last_euler_y - (float)EulerY;
    37. if (Mathf.Abs(y_change) > 180)
    38. {
    39.     // Passed 360
    40.     // Check direction we passed
    41.     if (y_change > 0)
    42.     {
    43.         // Add 360
    44.         euler_y_360_pass += 1;
    45.     }
    46.     else
    47.     {
    48.         // Sub 360
    49.         euler_y_360_pass -= 1;
    50.     }
    51.     // Recalc euler
    52.     EulerY = EulerY_org + (360 * euler_y_360_pass);
    53. }
    54.  
    55. // Check if z passed 360
    56. float z_change = (float)last_euler_z - (float)EulerZ;
    57. if (Mathf.Abs(z_change) > 180)
    58. {
    59.     // Passed 360
    60.     // Check direction we passed
    61.     if (z_change > 0)
    62.     {
    63.         // Add 360
    64.         euler_z_360_pass += 1;
    65.     }
    66.     else
    67.     {
    68.         // Sub 360
    69.         euler_z_360_pass -= 1;
    70.     }
    71.     // Recalc euler
    72.     EulerZ = EulerZ_org + (360 * euler_z_360_pass);
    73. }
    74.  
    75. // Save last
    76. last_euler_x = EulerX;
    77. last_euler_y = EulerY;
    78. last_euler_z = EulerZ;
     
    vonSchlank, dyupa, TheFlyHawk and 3 others like this.
  37. DavidSWu

    DavidSWu

    Joined:
    Jun 20, 2016
    Posts:
    183
    How does pitch isolation work if you are pointing (i.e. Z axis) straight up or straight down?
    This is a common case for us because people drive on walls.
     
  38. Aslan0227

    Aslan0227

    Joined:
    Mar 22, 2018
    Posts:
    1
    gameobject rotation (45,0,0)
    Debug.log(transform.eulerAngles.x);
    PRİNT = 45
    gameobject rotation (135,0,0)
    Debug.log(transform.eulerAngles.x);
    PRİNT = 45
    why !!!!!!!!!
     
  39. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,989
    Print all 3 values. The first gives (45,0,0). The second is (45,180,180), which is the same as (135,0,0) if you know how to read it. That's why people say not to try to read back angles after setting them.
     
    Bunny83 likes this.
  40. TheFlyHawk

    TheFlyHawk

    Joined:
    Mar 23, 2016
    Posts:
    58
    I just need this feature. Can I provide complete file code?
     
  41. UnityZelos

    UnityZelos

    Joined:
    Apr 3, 2019
    Posts:
    14
    Thank you
     
  42. The-any-Key

    The-any-Key

    Joined:
    Jan 19, 2019
    Posts:
    7
    Here is a simplified version that allow you to just drag this script as an component to an object and it will show the Euler angles in runtime.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class EulerGet : MonoBehaviour
    6. {
    7.     // ===========================================
    8.     // EULER CALC
    9.     // ===========================================
    10.     public double EulerX = 0;
    11.     public double EulerY = 0;
    12.     public double EulerZ = 0;
    13.     // Hold Euler list
    14.     private List<double[]> Euler_list;
    15.     // Hold last angle to calc angles over 360
    16.     private double last_euler_x;
    17.     private double last_euler_y;
    18.     private double last_euler_z;
    19.     // Hold 360 passes
    20.     private double euler_x_360_pass=0;
    21.     private double euler_y_360_pass=0;
    22.     private double euler_z_360_pass=0;
    23.     // ===========================================
    24.  
    25.     // Use this for initialization
    26.     void Start ()
    27.     {
    28.         // Init euler calc
    29.         init_euler_calc();
    30.     }
    31.    
    32.     // Update is called once per frame
    33.     void Update ()
    34.     {
    35.         // Update euler calc
    36.         update_euler_calc();
    37.     }
    38.  
    39.     // ===========================================
    40.     // EULER CALC
    41.     // ===========================================
    42.     public void init_euler_calc()
    43.     {
    44.         // Init first Euler as reference
    45.         float x = transform.eulerAngles.x / 360.0f * 2.0f * Mathf.PI;
    46.         float y = transform.eulerAngles.y / 360.0f * 2.0f * Mathf.PI;
    47.         float z = transform.eulerAngles.z / 360.0f * 2.0f * Mathf.PI;
    48.  
    49.         // Abbreviations for the various angular functions
    50.         double cx = Mathf.Cos(x * 0.5f);
    51.         double sx = Mathf.Sin(x * 0.5f);
    52.         double cy = Mathf.Cos(y * 0.5f);
    53.         double sy = Mathf.Sin(y * 0.5f);
    54.         double cz = Mathf.Cos(z * 0.5f);
    55.         double sz = Mathf.Sin(z * 0.5f);
    56.  
    57.         Vector4 xSandwich = new Vector4((float)sx, 0f, 0f, (float)cx);
    58.         Vector4 ySandwich = new Vector4(0f, (float)sy, 0f, (float)cy);
    59.         Vector4 zSandwich = new Vector4(0f, 0f, (float)sz, (float)cz);
    60.         Quaternion q5 = CreateVectorSandwich(ySandwich, xSandwich, zSandwich);
    61.  
    62.         /*
    63.         // Get current euler list
    64.         Euler_list = GetAllEulerAngles();
    65.         // Show list
    66.         foreach (double[] test_value in Euler_list)
    67.         {
    68.             Debug.Log("x:" + Mathf.Rad2Deg*test_value[0] + " y:" + Mathf.Rad2Deg * test_value[1] + " z:" + Mathf.Rad2Deg * test_value[2]);
    69.         }
    70.         */
    71.     }
    72.  
    73.     public void update_euler_calc()
    74.     {
    75.         // Get only Unity euler
    76.         double[] value = GetUnityEulerAngles();
    77.  
    78.         double EulerX_org = Mathf.Rad2Deg * value[0];
    79.         double EulerY_org = Mathf.Rad2Deg * value[1];
    80.         double EulerZ_org = Mathf.Rad2Deg * value[2];
    81.  
    82.         // Add 360 passes
    83.         EulerX = EulerX_org + (360 * euler_x_360_pass);
    84.         EulerY = EulerY_org + (360 * euler_y_360_pass);
    85.         EulerZ = EulerZ_org + (360 * euler_z_360_pass);
    86.  
    87.         // Check if x passed 360
    88.         float x_change = (float)last_euler_x - (float)EulerX;
    89.         if (Mathf.Abs(x_change) > 180)
    90.         {
    91.             // Passed 360
    92.             // Check direction we passed
    93.             if (x_change > 0)
    94.             {
    95.                 // Add 360
    96.                 euler_x_360_pass += 1;
    97.             }
    98.             else
    99.             {
    100.                 // Sub 360
    101.                 euler_x_360_pass -= 1;
    102.             }
    103.             // Recalc euler
    104.             EulerX = EulerX_org + (360 * euler_x_360_pass);
    105.         }
    106.  
    107.         // Check if y passed 360
    108.         float y_change = (float)last_euler_y - (float)EulerY;
    109.         if (Mathf.Abs(y_change) > 180)
    110.         {
    111.             // Passed 360
    112.             // Check direction we passed
    113.             if (y_change > 0)
    114.             {
    115.                 // Add 360
    116.                 euler_y_360_pass += 1;
    117.             }
    118.             else
    119.             {
    120.                 // Sub 360
    121.                 euler_y_360_pass -= 1;
    122.             }
    123.             // Recalc euler
    124.             EulerY = EulerY_org + (360 * euler_y_360_pass);
    125.         }
    126.  
    127.         // Check if z passed 360
    128.         float z_change = (float)last_euler_z - (float)EulerZ;
    129.         if (Mathf.Abs(z_change) > 180)
    130.         {
    131.             // Passed 360
    132.             // Check direction we passed
    133.             if (z_change > 0)
    134.             {
    135.                 // Add 360
    136.                 euler_z_360_pass += 1;
    137.             }
    138.             else
    139.             {
    140.                 // Sub 360
    141.                 euler_z_360_pass -= 1;
    142.             }
    143.             // Recalc euler
    144.             EulerZ = EulerZ_org + (360 * euler_z_360_pass);
    145.         }
    146.  
    147.         // Save last
    148.         last_euler_x = EulerX;
    149.         last_euler_y = EulerY;
    150.         last_euler_z = EulerZ;
    151.     }
    152.  
    153.     public static Vector4 SandwichProduct(Vector4 q1, Vector4 q2)
    154.     {
    155.         Vector4 q;
    156.         q.w = -q1.x * q2.x - q1.y * q2.y - q1.z * q2.z + q1.w * q2.w;
    157.         q.x = q1.x * q2.w + q1.y * q2.z - q1.z * q2.y + q1.w * q2.x;
    158.         q.y = -q1.x * q2.z + q1.y * q2.w + q1.z * q2.x + q1.w * q2.y;
    159.         q.z = q1.x * q2.y - q1.y * q2.x + q1.z * q2.w + q1.w * q2.z;
    160.  
    161.         return q;
    162.     }
    163.  
    164.     public static Quaternion CreateVectorSandwich(Vector4 a, Vector4 b, Vector4 c)
    165.     {
    166.         Vector4 v = SandwichProduct(SandwichProduct(a, b), c);
    167.         Quaternion q = new Quaternion(v.x, v.y, v.z, v.w);
    168.         return q;
    169.     }
    170.  
    171.     public double[,] CreateRotationMatrixFromQuaternion(double first, double second, double third, double w)
    172.     {
    173.         double[,] matrix = new double[3, 3];
    174.         double x = first;
    175.         double y = second;
    176.         double z = third;
    177.  
    178.         double m1_1 = 1.0 - 2.0 * (y * y + z * z);
    179.         double m1_2 = 2.0 * (x * y - z * w);
    180.         double m1_3 = 2.0 * (x * z + y * w);
    181.  
    182.         double m2_1 = 2.0 * (x * y + z * w);
    183.         double m2_2 = 1.0 - 2.0 * (x * x + z * z);
    184.         double m2_3 = 2.0 * (y * z - x * w);
    185.  
    186.         double m3_1 = 2.0 * (x * z - y * w);
    187.         double m3_2 = 2.0 * (y * z + x * w);
    188.         double m3_3 = 1.0 - 2.0 * (x * x + y * y);
    189.  
    190.         matrix[0, 0] = m1_1; matrix[0, 1] = m1_2; matrix[0, 2] = m1_3;
    191.         matrix[1, 0] = m2_1; matrix[1, 1] = m2_2; matrix[1, 2] = m3_3;
    192.         matrix[2, 0] = m3_1; matrix[2, 1] = m3_2; matrix[2, 2] = m3_3;
    193.  
    194.         return matrix;
    195.     }
    196.  
    197.     public double[] CreateEulerFromRotationMatrix(double[,] matrix, int idx1, int idx2, int idx3)
    198.     {
    199.         double[] angles = new double[3];
    200.         double ftany = matrix[2, 1];
    201.         double ftanx = matrix[2, 2];
    202.         double first = System.Math.Atan2(ftany, ftanx);
    203.         double stany = matrix[1, 0];
    204.         double stanx = matrix[0, 0];
    205.         double second = System.Math.Atan2(stany, stanx);
    206.         double tsiny = matrix[2, 0];
    207.         double third = System.Math.Asin(-1.0 * tsiny);
    208.  
    209.         angles[idx1] = first;
    210.         angles[idx2] = second;
    211.         angles[idx3] = third;
    212.  
    213.         return angles;
    214.     }
    215.  
    216.     public double[] GetUnityEulerAngles()
    217.     {
    218.         // Get local transform
    219.         Quaternion q;
    220.         q.x = transform.localRotation.x;
    221.         q.y = transform.localRotation.y;
    222.         q.z = transform.localRotation.z;
    223.         q.w = transform.localRotation.w;
    224.         // Hold return values
    225.         double[,] matrices;
    226.         double[] angles;
    227.         // Get needed matrix
    228.         matrices=CreateRotationMatrixFromQuaternion(q.z, q.x, q.y, q.w);
    229.         // Calc Unity Euler
    230.         angles=CreateEulerFromRotationMatrix(matrices, 2, 1, 0);
    231.         // Return Unity euler
    232.         return angles;
    233.     }
    234.  
    235.     public List<double[]> GetAllEulerAngles()
    236.     {
    237.         // Get local transform
    238.         Quaternion q;
    239.         q.x = transform.localRotation.x;
    240.         q.y = transform.localRotation.y;
    241.         q.z = transform.localRotation.z;
    242.         q.w = transform.localRotation.w;
    243.  
    244.         List<double[,]> matrices = new List<double[,]>();
    245.         List<double[]> angles = new List<double[]>();
    246.  
    247.         matrices.Add(CreateRotationMatrixFromQuaternion(q.x, q.y, q.z, q.w));
    248.         matrices.Add(CreateRotationMatrixFromQuaternion(q.x, q.z, q.y, q.w));
    249.         matrices.Add(CreateRotationMatrixFromQuaternion(q.y, q.x, q.y, q.w));
    250.         matrices.Add(CreateRotationMatrixFromQuaternion(q.y, q.y, q.x, q.w));
    251.         matrices.Add(CreateRotationMatrixFromQuaternion(q.z, q.x, q.y, q.w));
    252.         matrices.Add(CreateRotationMatrixFromQuaternion(q.z, q.y, q.x, q.w));
    253.  
    254.         for (int i1 = 0; i1 < 6; i1++)
    255.         {
    256.             angles.Add(CreateEulerFromRotationMatrix(matrices[i1], 0, 1, 2));
    257.             angles.Add(CreateEulerFromRotationMatrix(matrices[i1], 0, 2, 1));
    258.             angles.Add(CreateEulerFromRotationMatrix(matrices[i1], 1, 0, 2));
    259.             angles.Add(CreateEulerFromRotationMatrix(matrices[i1], 1, 2, 0));
    260.             angles.Add(CreateEulerFromRotationMatrix(matrices[i1], 2, 0, 1));
    261.             angles.Add(CreateEulerFromRotationMatrix(matrices[i1], 2, 1, 0));
    262.         }
    263.  
    264.         return angles;
    265.  
    266.     }
    267. }
    268.  
     
  43. Deleted User

    Deleted User

    Guest

    Hello!

    This is a simple script showing how you can get inspector like values of any transform.

    Vector3 angle = transform.eulerAngles;
    float x = angle.x;
    float y = angle.y;
    float z = angle.z;

    if (Vector3.Dot(transform.up, Vector3.up) >= 0f)
    {
    if (angle.x >= 0f && angle.x <= 90f)
    {
    x = angle.x;
    }
    if (angle.x >= 270f && angle.x <= 360f)
    {
    x = angle.x - 360f;
    }
    }
    if (Vector3.Dot(transform.up, Vector3.up) < 0f)
    {
    if (angle.x >= 0f && angle.x <= 90f)
    {
    x = 180 - angle.x;
    }
    if (angle.x >= 270f && angle.x <= 360f)
    {
    x = 180 - angle.x;
    }
    }

    if (angle.y > 180)
    {
    y = angle.y - 360f;
    }

    if (angle.z > 180)
    {
    z = angle.z - 360f;
    }

    Debug.Log(angle + " :::: " + Mathf.Round(x) + " , " + Mathf.Round(y) + " , " + Mathf.Round(z));
     
  44. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,500
    Thx @ForgeArts for the script I put it in clean.

    Works but with limitation of X -90° +90° only

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. // Print transform rotation only up to 90° of this object
    4. // from: https://forum.unity.com/threads/solved-how-to-get-rotation-value-that-is-in-the-inspector.460310/#post-4564687
    5. public class InspectRotation_Simple : MonoBehaviour
    6. {
    7.     void Update()
    8.     {
    9.         if (Input.GetKeyDown(KeyCode.Space))
    10.         {
    11.             Vector3 angle = transform.eulerAngles;
    12.             float x = angle.x;
    13.             float y = angle.y;
    14.             float z = angle.z;
    15.  
    16.             if (Vector3.Dot(transform.up, Vector3.up) >= 0f)
    17.             {
    18.                 if (angle.x >= 0f && angle.x <= 90f)
    19.                 {
    20.                     x = angle.x;
    21.                 }
    22.                 if (angle.x >= 270f && angle.x <= 360f)
    23.                 {
    24.                     x = angle.x - 360f;
    25.                 }
    26.             }
    27.             if (Vector3.Dot(transform.up, Vector3.up) < 0f)
    28.             {
    29.                 if (angle.x >= 0f && angle.x <= 90f)
    30.                 {
    31.                     x = 180 - angle.x;
    32.                 }
    33.                 if (angle.x >= 270f && angle.x <= 360f)
    34.                 {
    35.                     x = 180 - angle.x;
    36.                 }
    37.             }
    38.  
    39.             if (angle.y > 180)
    40.             {
    41.                 y = angle.y - 360f;
    42.             }
    43.  
    44.             if (angle.z > 180)
    45.             {
    46.                 z = angle.z - 360f;
    47.             }
    48.  
    49.             Debug.Log(angle + " :::: " + Mathf.Round(x) + " , " + Mathf.Round(y) + " , " + Mathf.Round(z));
    50.         }
    51.     }
    52. }
     
    Last edited: May 23, 2019
  45. Shippety

    Shippety

    Joined:
    May 9, 2014
    Posts:
    31
    This is just what I needed to know, thanks!
     
  46. SIRIUSTECHSOLUTIONS

    SIRIUSTECHSOLUTIONS

    Joined:
    Apr 14, 2016
    Posts:
    9
    Hello, just try this one float angle = System.Math.Round((double)transform.eulerAngles.y, 1);
     
  47. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,989
    Not an answer. Read the rest of the Q: when the angle is 0, the Inspector might show 0, or 360, 720, -360, or it might even show 180 or -180. They want to know which one, from inside of the program.
     
    DonLoquacious likes this.
  48. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,746
  49. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,989
    prosto666, vonSchlank and AlanMattano like this.
  50. SpaceManDan

    SpaceManDan

    Joined:
    Aug 3, 2013
    Posts:
    15

    So simple. Thousands of words from so many people... Yet, this is all anybody really needed. Thanks!
     
Thread Status:
Not open for further replies.