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

roll, pitch, and yaw from quaternion

Discussion in 'Scripting' started by Sortasoft, Oct 12, 2010.

  1. Sortasoft

    Sortasoft

    Joined:
    Feb 24, 2009
    Posts:
    59
    Does anyone have any Unity code to get roll, pitch, and yaw from a quaternion? I've found several generic formulas online but they are inconsistent between each other, and none seem to work perfectly.

    Thanks!
     
  2. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,602
    .eulerAngles contains the information you need.
     
  3. Sortasoft

    Sortasoft

    Joined:
    Feb 24, 2009
    Posts:
    59
    Thank you for the reply. The problem with the euler angles is that since I'm rotating about all 3 axis, they don't properly give me the rotation for any individual axis. I need to be able to get just the roll, for instance, in relation to the object itself.

    Here's some example code, though it doesn't seem to work properly:
    http://sunday-lab.blogspot.com/2008/04/get-pitch-yaw-roll-from-quaternion.html
     
  4. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    I think you might be thinking about the problem in the wrong way.

    The fact that you're rotating about multiple axes doesn't really matter. (Well, it might, but I don't think that's the problem here.) There's a couple of things though that will affect the result of the extraction. The first is axis order; Unity uses the order Z-X-Y, which is fairly sensible given Unity's conventions. The second is the algorithm used. Multiple Euler-angle triples can be used to describe the same orientation, so unless you know exactly how the extraction is being performed, you can't expect to get any particular values back. (Even if you build a rotation from a set of Euler angles and then immediately extract them again, you might not get the same angles back that you put in.)

    The key problem though is that an object by itself does not have a roll angle (or a pitch or yaw angle, for that matter). Imagine a ship floating in the void of space with absolutely no frame of reference; what is its roll? The answer is that there's no way to know; in fact, the question doesn't really even make any sense.

    The concept of (absolute) roll implies that there's a frame of reference, more or less, so if you need to know the 'roll' of your object, the first step will be to establish that frame of reference. A common problem, for example, is to determine the roll of a vehicle relative to the horizon or to the ground plane. This can be determined using some simple vector math; Euler angles needn't be involved.

    In any case, I'm fairly confident that an Euler-angle conversion isn't what you're looking for here. Can you describe the specific problem that you're trying to solve?
     
  5. Sortasoft

    Sortasoft

    Joined:
    Feb 24, 2009
    Posts:
    59
    Jesse, thanks very much. That makes a lot of sense. My frame of reference would be a rotation of 0,0,0.

    Specifically, I have a quaternion that I'm getting from the Prime31 devicemotion plugin (http://www.prime31.com/unity/), and I can use it to rotate an object properly. But I also want to know the specific pitch, roll, and yaw from that quaternion (or of the object, they should be the same).
     
  6. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    You can certainly extract a set of Euler angles from a quaternion, but as mentioned earlier there are a lot of variables, and the angles you get may not always be what you're expecting.

    May I ask what you need the Euler angles for?
     
  7. Sortasoft

    Sortasoft

    Joined:
    Feb 24, 2009
    Posts:
    59
    Jesse, I don't necessarily need the Euler angles. I need to know the roll, pitch, and yaw individually to display how much the iPhone moved in one of those directions. So for example, recording how much the iPhone was tilted to the left. (It's a non-game utility.)

    Is it maybe possible to get the Z euler angle , then rotate by -Z, get the X euler angle, rotate by -X, and finally get the Y euler angle? Or something along these lines?
     
  8. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    Hm, I'm not sure if I understand the problem well enough to say for sure.

    Is this readout supposed to display in absolute terms the phone's orientation with respect to some reference orientation, but in Euler angles?

    If so, the closest thing I can think of to a solution right now would be to extract a set of 'canonical' Euler angles from the orientation quaternion. Canonical Euler angles are processed in such a way that even though multiple sets of Euler angles can describe the same orientation, you're still guaranteed to get angles that fall within certain constraints. I don't know if the Euler angles returned by Unity are canonical though (I suspect they aren't, but I'm not sure).

    If you need some additional references on this, let me know and I can post some links.
     
  9. Sortasoft

    Sortasoft

    Joined:
    Feb 24, 2009
    Posts:
    59
    Jesse, yes the program should basically tell me the number of degrees that the phone has rolled, from an initial position (either the starting position, or from a non-rotated position). You don't have to think of it as just the phone, because it controls a 3D model, which works, and I'd be happy just to get the roll, pitch and yaw of that model from the quaternion.
     
  10. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    The best solution I can think of at the moment is to extract a set of Euler angles from the quaternion and display those angles (which I think is what you intended initially).

    That leaves only what order to extract the angles in, and what algorithm to use to extract them. There's really no one right way to do it, and I'm pretty sure that whatever method you use to extract the angles, you may still occasionally end up with angles that aren't entirely intuitive.

    I suppose you could also write code to determine the object's yaw with respect to the initial facing direction, and the pitch and roll with respect to the ground plane, but I don't think the resulting angles would be a 'proper' set of Euler angles (in the sense that you could combine them to yield the object's current orientation).

    Sorry I can't be more helpful, but I'll admit I still don't fully understand the specifications of the problem. It sounds like you're just looking for an Euler-angle conversion, and that the only issues in question are what order to extract the rotations in, and what algorithm to use to extract them. But, I might be missing something somewhere.
     
  11. Sortasoft

    Sortasoft

    Joined:
    Feb 24, 2009
    Posts:
    59
    My understanding is that Euler angles are not necessarily the same as roll, pitch, and yaw. Am I mistaken?
     
  12. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    I believe there's some fluidity in the terminology used (although I may be mistaken about that). The Wikipedia article on Euler angles (which I assume is more or less accurate) has some information on the different terminology and conventions used. The article mentions that the different conventions are divided into 'Tait-Bryan' angles and what are sometimes called 'proper' Euler angles, but that the term 'Euler angles' can be used inclusively to describe all twelve possible axis-order conventions.

    In game development at least, it seems it's common to use the term 'Euler angles' in the inclusive sense. Furthermore, it seems it's pretty uncommon to use repeating axis orders (e.g. xyx, xzx, etc.) in a game development context; non-repeating orders (xyz, xzy, etc.) seem to be more commonly used.

    As for 'yaw', 'pitch', and 'roll', those terms are generally associated with non-repeating axis orders, which, when using the more specific terminology, would actually be Tait-Bryan angles, I believe. However, when using the term 'Euler angles' in the general sense, it covers those axis orders as well, so it seems that to use the terms 'yaw', 'pitch', and 'roll' with respect to Euler angles would not be incorrect.

    Whatever the case may be, it's certainly quite common in the game development community to use the term 'Euler angles' to refer to non-repeating axis orders, and to use the terms 'yaw', 'pitch', and 'roll' to refer to the individual angles used in the rotation sequence. Obviously common usage doesn't always indicate correctness (see 'binormal', for example), but in this case at least, the common usage isn't incorrect as far as I know.

    Maybe others will weigh in on that though.
     
  13. Groucho

    Groucho

    Joined:
    Dec 24, 2009
    Posts:
    73
    I'm looking for a good solution for this too. Body axis rotations are what I'm looking for. Pitch, roll yaw as defined in CoreMotion don't appear to be body fixed.

    For example, suppose I hold my iPhone in landscape mode. When face one direction and roll the phone (turn it like a steering wheel), I get correct orientation by accessing iOS's CMDeviceMotion.attitude.yaw. However, if I turn by entire body to face 90 degrees from my original direction, a roll motion of the phone now outputs in pure pitch. A body-axis coordinate system would keep roll as roll for any yaw orientation.

    It looks like CoreMotion Teapot (from WWDC2010) does something very close. It does a 3x3 matrix transformation applied to an object though. For control schemes, it'd be nice to just have a pure body-axis roll (and pitch) variable to use.

    Time to dust off the college textbooks I guess. If anyone figures this out using the Prime31 DeviceMotion plug-in, please share!
     
  14. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,602
    Nothing prevents you doing this in unity. Quaternion.Euler() is global axis, not local axis for example. which you then can apply as rotation to an object

    Using Eulers / Matrices has one major drawback and thats the reason why they are not used, especially not if you want to use the accelerometer - gyro: Gimbal Lock
    Should you not have heard of this yet, then you will soon find out what it is when you get an insanely spinning object on screen on the slightest movement ;)
     
  15. Nikolay116

    Nikolay116

    Joined:
    Mar 21, 2010
    Posts:
    421
    Watch out, I warn you not to use "Gimbal Lock" here.
     
    Last edited: Oct 17, 2010
  16. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    We just had this same discussion recently in this thread. Although it's a common misconception that matrices behave differently than quaternions with respect to gimbal lock, this is incorrect (matrices and quaternions have exactly the same behavior with respect to gimbal lock).
     
    Venecius likes this.
  17. Sortasoft

    Sortasoft

    Joined:
    Feb 24, 2009
    Posts:
    59
    I got this to work, and wanted to share the relevant code in case it can help anyone in the future. I did have to "unwind" each of the coordinates.

    Code (csharp):
    1.  
    2.     float getPan(Transform t){
    3.         return t.localEulerAngles.z;
    4.     }
    5.    
    6.     float getRoll(Transform originalTransform){
    7.         GameObject tempGO = new GameObject();
    8.         Transform t = tempGO.transform;
    9.         t.localRotation = originalTransform.localRotation;
    10.        
    11.         t.Rotate(0,0, t.localEulerAngles.z * -1);
    12.        
    13.         GameObject.Destroy(tempGO);
    14.         return t.localEulerAngles.x;
    15.     }
    16.    
    17.     float getTilt(Transform originalTransform){
    18.         GameObject tempGO = new GameObject();
    19.         Transform t = tempGO.transform;
    20.         t.localRotation = originalTransform.localRotation;
    21.        
    22.         t.Rotate(0,0, t.localEulerAngles.z * -1);
    23.         t.Rotate(t.localEulerAngles.x * -1,0,0);
    24.        
    25.         GameObject.Destroy(tempGO);
    26.         return t.localEulerAngles.y;
    27.     }
     
  18. Groucho

    Groucho

    Joined:
    Dec 24, 2009
    Posts:
    73
    Thanks! I can't wait to give this a try.
     
  19. ruge.rux

    ruge.rux

    Joined:
    Jul 7, 2012
    Posts:
    1
    HI, I have Pan, Roll and Tilt, how do I get transform.rotation?

    Thanks in advance.
     
  20. curtfl

    curtfl

    Joined:
    Jan 9, 2014
    Posts:
    2
    Had this same issue creating an artificial horizon, ended up with a much easier way, project the vector on the X/Z plane then take its angle with the original view, viola.

    Code (csharp):
    1.  
    2. float pitchAngle = Vector3.Angle( new Vector3(transform.forward.x, 0, transform.forward.z), transform.forward );
    3.  
     
  21. dhinson919

    dhinson919

    Joined:
    Jul 17, 2016
    Posts:
    1
    One technique for doing this kind of thing is to project two vectors, a fixed one and the variable one, onto a common plane and measure the angle between them. I did a similar thing with a game mechanic where there were ships orbiting a planet and I wanted to represent orbit angles as a single 0-360 float value relative to planet north. Each orbiter had its own transform relative to the planet where the transform.right vector pointed to the planet.

    Code (CSharp):
    1. var planetNorth = Vector3.ProjectOnPlane(planet.transform.up, orbiter.transform.right);
    2. var orbiterUpAngle = Vector3.Angle(Vector3.ProjectOnPlane(orbiter.transform.up, orbiter.transform.right), planetNorth);
    This gave the angle of the orbiter's transform.up vector relative to the planet north. But Vector3.Angle only reports values in the range 0-180 so I had to take an additional angle measure using the orbiter's transform.forward vector to derive the 0-360 azimuth.

    Code (CSharp):
    1. var orbiterForwardAngle = Vector3.Angle(Vector3.ProjectOnPlane(orbiter.transform.forward, orbiter.transform.right), planetNorth);
    2. float orbiterAzimuth = (orbiterForwardAngle >= 90f) ? orbiterUpAngle : 360f - orbiterUpAngle;
    There's probably a clever way to get the same information using fewer calculations but this didn't need to be executed every frame and was easy to wrap my mind around. For a pitch/roll/yaw angle relative to world space it seems all you'd have to do is substitute Vector3.up for planet.transform.up, etc.
     
  22. nicemankit

    nicemankit

    Joined:
    Feb 13, 2019
    Posts:
    1
    Sortasof :
    But you can code the function of the rotate, otherwise I don’t have to work at all ?
     
unityunity