Xbox LIVE Indie Games
Sort Discussions: Previous Discussion Next Discussion
Page 1 of 2 (26 posts) 1 2 Next >

Converting Quaternion to Euler angles

Last post 7/31/2011 5:04 AM by AK-STUDIO. 25 replies.
  • 9/4/2007 5:54 PM

    Converting Quaternion to Euler angles

    ...at least I think that's the right terminology.

    The objects in my project originally contained their orientation in Yaw/Pitch/Roll components, and I'm now revamping it to use a sort of hybrid between that and Quaternions instead. I admit that I've never dealt with Quaternions prior to this, so I know next to nothing about them. When I first made the conversion, everything in my program started quivering and spinning chaotically. While I did manage to correct that, after further testing, I concluded that my conversions are still incorrect. Does anyone have the equations, or equally suitable method, to find Yaw/Pitch/Roll from a Quaternion? I found the following from Wikipedia:


    (That's supposedly roll, pitch, and yaw respectively)

    In my code, it looks like this:

    public static Vector3 QuaternionToEuclidean(Quaternion rotation)
    {
    Vector3 rotationaxes = new Vector3();
    rotationaxes.X = (float)Math.Asin(2 * (rotation.W * rotation.Y - rotation.Z * rotation.X));
    float test = rotation.X * rotation.Y + rotation.Z * rotation.W;
    if (test == .5f)
    {
    rotationaxes.Y = 2 * (float)Math.Atan2(rotation.X, rotation.W);
    rotationaxes.Z = 0;
    }
    else if (test == -.5f)
    {
    rotationaxes.Y = -2 * (float)Math.Atan2(rotation.X, rotation.W);
    rotationaxes.Z = 0;
    }
    else
    {
    rotationaxes.Y = (float)Math.Atan(2 * (rotation.W * rotation.Z + rotation.Y * rotation.Y) / (1 - 2 * (rotation.Y * rotation.Y + rotation.Z * rotation.Z)));
    rotationaxes.Z = (float)Math.Atan(2 * (rotation.W * rotation.X + rotation.Y * rotation.Z) / (1 - 2 * (rotation.X * rotation.X + rotation.Y * rotation.Y)));
    }
    return rotationaxes;
    }
    (X is pitch, Y is Yaw, Z is roll)

    But that gave very wrong results. Anyone know how to correct it?

  • 9/4/2007 7:37 PM In reply to

    Re: Converting Quaternion to Euler angles

    I'm unable to grasp what you are trying to accomplish. A quaternion is useful for rotating an object around an arbitrary axis that you specify with a vector. I see no value in trying to convert between a quaternion and euler angles. If you describe your goal in more detail, perhaps I or someone else will be able to offer some thoughts.
  • 9/4/2007 8:56 PM In reply to

    Re: Converting Quaternion to Euler angles

    Ed,

    I've not had need to convert from quaternions to Euler before so I am also curious if this is more than an academic exercise.

    Just looking at your implementation of the wiki formula, I wonder if you are thinking of a quaternion in xna being expressed as (w,x,y,z) instead of (x,y,z,w).

    The wiki uses (q0,q1,q2,q3)  & I believe that should convert to  q0==x,q1==y,q2==z,q3==w.

    So for instance;
    rotationaxes.X = (float)Math.Asin(2 * (rotation.W * rotation.Y...

    should be;

    rotationaxes.X = (float)Math.Asin(2 * (rotation.X * rotation.Z...

    and so on.

  • 9/4/2007 9:39 PM In reply to

    Re: Converting Quaternion to Euler angles

    I ran into this when I first started learning about rotations. I was trying to treat quaternion rotations just like euler rotations.

    At that time, I tried to do conversions, and then I found that it was a waste going through all the conversions, and just ended up changing all my rotations to euler rotations and getting rid of all quaternion references. Unless gimbal lock is going to be an issue with your program you probably won't need quaternions anyhow.

  • 9/5/2007 12:29 PM In reply to

    Re: Converting Quaternion to Euler angles

    Lord Ikon: yeah, that's what I've been doing originally, but as Kyle W pointed out above, a quaternion is useful for rotating about an arbitrary axis, which is nearly impossible (if not impossible) to do with Euler axes.

    Steve: I was under the impression that the q0 component was the "scalar" of the quaternion (I dunno if that's the correct term 'cause I don't know quaternions that well), since, I believe, the quaternions were somehow defined as w + xi + yj + zk elsewhere in the article, so I thought 0 would be w. Nevertheless, thanks, and I'll try that interpretation later and see if I have any more success.

    Kyle and Steve: The reason for doing it this way is to try to unite the two systems as one for the objects in my program. That is, each object can be given a yaw, pitch, and roll (which is easy using XNA's Quaternion.CreateFromYawPitchRoll method), but I wanted it to also be able to increment these properties as well (object.Yaw += Math.Pi/2). The way I'm currently doing this is keeping track of both a Quaternion and a Vector3 containing the Euler rotations. If the yaw, pitch, or roll change, then it updates the Quaternion with these values, and so far that works fine. If the Quaternion changes (such as through an arbitrary axis rotation), then I want it to update the the Vector3, and thus I need these equations to do so. Basically, it's just for flexibility, so I can treat the rotation as either, and receive the benefits of both systems.

  • 9/5/2007 3:06 PM In reply to

    Re: Converting Quaternion to Euler angles

    Well, I'm not a math guru, so the only other suggestion I can offer you would be to use the Reflector .NET decompiler to examine the Quaternion.CreateFromYawPitchRoll() method. This might enable you to reverse-solve the mathematics it uses in order to go from quaternion back to yaw pitch roll. Here's a link:

    http://msdn2.microsoft.com/en-us/vcsharp/aa336818.aspx

  • 9/5/2007 7:34 PM In reply to

    Re: Converting Quaternion to Euler angles

    Yeah, I took a look at that too, in hopes to try to figure out which element was which...

    public static Quaternion CreateFromYawPitchRoll(float yaw, float pitch, float roll)
    {
    Quaternion quaternion;
    float num9 = roll * 0.5f;
    float num6 = (float) Math.Sin((double) num9);
    float num5 = (float) Math.Cos((double) num9);
    float num8 = pitch * 0.5f;
    float num4 = (float) Math.Sin((double) num8);
    float num3 = (float) Math.Cos((double) num8);
    float num7 = yaw * 0.5f;
    float num2 = (float) Math.Sin((double) num7);
    float num = (float) Math.Cos((double) num7);
    quaternion.X = ((num * num4) * num5) + ((num2 * num3) * num6);
    quaternion.Y = ((num2 * num3) * num5) - ((num * num4) * num6);
    quaternion.Z = ((num * num3) * num6) - ((num2 * num4) * num5);
    quaternion.W = ((num * num3) * num5) + ((num2 * num4) * num6);
    return quaternion;
    }

    To simplify for easy recognition:

    X = cos(yaw/2) * sin(pitch/2) * cos(roll/2) + sin(yaw/2) * cos(pitch/2) * sin(roll/2)
    Y = sin(yaw/2) * cos(pitch/2) * cos(roll/2) - cos(yaw/2) * sin(pitch/2) * sin(roll/2)
    Z = cos(yaw/2) * cos(pitch/2) * sin(roll/2) - sin(yaw/2) * sin(pitch/2) * cos(roll/2)
    W = cos(yaw/2) * cos(pitch/2) * cos(roll/2) + sin(yaw/2) * sin(pitch/2) * sin(roll/2)

    Then, comparing with the Wikipedia article's equation:

    It looks like W (cos cos cos + sin sin sin) is the first element in Wiki's equation. (However, that also seems to imply that Y is second, X is third, and Z is fourth, which doesn't make too much sense... Unless perhaps Wiki uses a different coordinate system.) Anyway, with that in mind, maybe I just have to rearrange the four Quaternion elements in that equation I posted at the beginning...?

  • 9/6/2007 8:33 AM In reply to

    Re: Converting Quaternion to Euler angles

    Ok, I can't see any way to reverse-solve those equations, although perhaps I'm just not smart enough.

    However, I think I have a solution for you. Let's assume your model is an airplane. Let's then assume that the default position for your airplane has its nose facing down the negative Z axis. In your game, create a Vector3 object called NoseVector and set it to (0,0,-1) such that it is aligned with the nose of the airplane. Also create a Vector3 object called AirplaneUpVector and set it to (0,1,0). Now, whenever you apply a rotation to the airplane either through Yaw-Pitch-Roll or via some arbitrary axis (for a physics simulation perhaps), apply the same rotation to the NoseVector and AirplaneUpVector objects. This will keep the NoseVector aligned with the nose of the airplane and the AirPlaneUpVector aligned with the top side of the airplane. Make sure you only apply the rotation components to the NoseVector and AirplaneUpVector objects and not the translation components.

    Now, after rotating the airplane to some arbitrary position, we can calculate the current Yaw, Pitch, and Roll by manipulating these vectors and calculating their angles relative to the world axes. For reference, here are some links showing you how to calculate the angle between two vectors:

    http://www.google.com/search?hl=en&safe=off&rls=com.microsoft%3Aen-US&q=%22angle+between+two+vectors%22

    So the way you would go about it is this:

    As I said, after rotating the airplane to some arbitrary position, you will have also applied the same rotations to NoseVector and AirplaneUpVector.

    To calculate the Yaw, make a copy of NoseVector and set the Y component in the copy to zero. This will move the copy vector into the XZ plane. Normalize the copy vector and then calculate its angle with the negative Z axis vector (0,0,-1). This angle is your Yaw. Note that if the airplane is pointed straight up or straight down, this calculation will not work because Yaw is undefined in these scenarios. You'll have to decide how you want to set the Yaw in these cases.

    To calculate the Pitch, calculate the angle between NoseVector and the negative Y axis (0,-1,0) and then subtract 90 degrees from the result. This angle is your Pitch.

    To calculate the Roll, make a copy of AirplaneUpVector. Rotate the copy around the global Y axis by the negative Yaw angle that you calculated above. Then, rotate it around the global X axis by the negative Pitch angle that you calculated above. This should align the copy of the AirplaneUpVector back onto the global XY plane as if the airplane was in its default position (pointing its nose down the negative Z axis), but with the Roll angle already applied. You can then calculate the angle between the copy vector and the positive Y axis (0,1,0) to determine the Roll angle. However, I expect you'll get a positive angle as a result both when the airplane is rolled to the left or the right, so you'll need to make the angle negative if the X coordinate in the copy of AirplaneUpVector is less than zero. This is your Roll angle.

    However, if you were unable to calculate a Yaw angle above because the airplane is pointing straight up or straight down (X and Z in NoseVector both equal zero), then you cannot use the preceding method to calculate the Roll angle because you will not be able to rotate the copy of AirplaneUpVector by the negative Yaw angle. In this scenario, the AirplaneUpVector will lie directly in the global XZ plane. So instead of using the method in the previous paragraph to calculate the Roll angle, simply calculate the angle between AirplaneUpVector and the negative Z axis (0,0,-1). If the X coordinate in AirplaneUpVector is less than zero, make the angle negative, and use this as your Roll angle. For things to remain consistent, it may be necessary to set Yaw to zero in this situation, but I'm not certain about that.

    Well hopefully these suggestions will meet your needs, but if not, I don't know what to tell you. Good luck. :)

  • 9/6/2007 8:59 AM In reply to

    Re: Converting Quaternion to Euler angles

    Correction to the last paragraph:

    However, if you were unable to calculate a Yaw angle above because the airplane is pointing straight up or straight down (X and Z in NoseVector both equal zero), then you cannot use the preceding method to calculate the Roll angle because you will not be able to rotate the copy of AirplaneUpVector by the negative Yaw angle. In this scenario, the AirplaneUpVector will lie directly in the global XZ plane. So instead of using the method in the previous paragraph to calculate the Roll angle, simply calculate the angle between AirplaneUpVector and the negative Z axis (0,0,-1). If the X coordinate in AirplaneUpVector is less than zero and the Y coordinate in NoseVector is less than zero, make the angle negative. Likewise, if the Y coordinate in NoseVector is greater than zero and X coordinate in AirplaneUpVector is greater than zero, make the angle negative. Use this as your Roll angle. For things to remain consistent, it may be necessary to set Yaw to zero in this situation, but I'm not certain about that.

  • 9/6/2007 9:17 AM In reply to

    Re: Converting Quaternion to Euler angles

    Wow, very thorough reply! Thanks! It's not the exact solution I was looking for, but if encapsulated in a class, should work just as well as any other. I will have to give this one a try later.

    If I understood correctly, you're saying I should maintain the Nose and Up vectors within the object, rotating along with Quaternion as changes are made. As an extention of your solution, see if this alternative makes sense and theoretically works: Let's say I've got some Quaternion that defines an objects rotation; it can rotate freely and whatnot. When such a conversion to Euler rotations is demanded, we set those Nose and Up vectors to their default values ((0,0,-1) and (0,1,0), respectively), transform them both by whatever the Quaternion currently is (it turns out XNA has a "Vector3.Transform(Vector3, Quaternion)" method; I didn't know that until just now), and then calculate the Yaw, Pitch, and Roll according to your method above. Basically, the same thing, except the two vectors aren't recorded, just found whenever needed. Think that would work? If so, any better or worse?

    (Oh, and as an FYI for your future reference, you can edit your prior posts to correct yourself. There should be an "Edit" link in your own posts.)

  • 9/6/2007 9:35 AM In reply to

    Re: Converting Quaternion to Euler angles

    Sounds plausible as long as the quaternion or matrix fully describes the current rotational orientation of the model. If so, then that would be slightly more efficient, yes.
  • 9/6/2007 9:48 AM In reply to

    Re: Converting Quaternion to Euler angles

    Yes, the Quaternion would describe the rotation entirely, as the model is drawn with a rotation defined strictly by the Quaternion alone.

    I only foresee one small problem, and that's in terms of efficiency. I forget if I mentioned earlier, the reason I want to be able to use both Quaternions and Euler rotations is to use Yaw/Pitch/Roll and arbitrary axis rotations at will. In the solution I proposed just above, to adjust, say, Yaw, I'd need to first calculate the current Yaw from the Quaternion, increment it, and then set the Quaternion according to the new Euler values. That could be a problem considering all the trigonometry involved, if such adjustments would be made on every model every frame. So, a better solution, and the one I've been developing all along here, is to keep track of both the Quaternion and Euler rotations, and if one changes, it invalidates the other, thereby only converting when necessary. At least now I have this alternate method of converting to Euler rotations, which could, strangely, prove more efficient than those blasted complex algebra equations listed above...

  • 9/6/2007 10:03 AM In reply to

    Re: Converting Quaternion to Euler angles

    Well, efficient or not, the suggestions I gave were the only things I could come up with that might actually work. At least I think it will work. I offer no warranties. :)

    One last comment for you... as you can probably visualize, when the airplane is pointed straight up or straight down, the Roll angle is indistinguishable from the Yaw angle. I gave you a method for calculating the Roll angle in this scenario by calculating the angle between the AirplaneUpVector and the negative Z axis. You could in fact take the resulting angle and assign it to Yaw instead of Roll, and assign zero to Roll. This might give a more desirable result for the behavior of the airplane.

    Cheers!

  • 9/6/2007 10:21 AM In reply to

    Re: Converting Quaternion to Euler angles

    I've done similar conversions with this method, and yeah, it should work, perhaps with a bit of fine tuning.

    And yes, I've considered the Yaw/Roll exchange too, and will probably do just that. Thanks again for your help, and I'll let you know how it goes when I get a chance to test it!

  • 9/6/2007 12:41 PM In reply to

    Re: Converting Quaternion to Euler angles

    Ed, Kyle,

    I’m way behind the two of you in figuring this out but a thought I had to convert Quaternion to euler  is below but take it only as a possibility (kind of thinking out loud).

    1.         1. The dot product of two unit vectors = the cosine of the angular difference.

    2.         2. Angle = the ArcCos(cosine)

    3.         3. So;   Acos(Vector3.Dot(vec1, vec2)) = angle diff between two vec1 & vec2.

    So in your update call;

                quatRot *= Quaternion.CreateFromYawPitchRoll(?,?,?);

    Matrix matrixRot = Matrix.CreateFromQuaternion(quatRot);

    Vector3 fwd = matrixRot.Forward;
    fwd.X = 0; //rotate model axis gizmo so it & eular gizmo are coplaner along x/z plane
    fwd.Normalize(); // because I think it is important
    // to have unit vectors for dot product equation

    Vector3 right = matrixRot.Right;
    right.Z = 0;
    right.Normalize();
    Vector3 up = matrixRot.Up;
    up.X = 0;
    up.Normalize();

    float xAngle = (float)Math.Acos(Convert.ToDouble(Vector3.Dot(fwd, Vector3.Forward)));

    float yAngle = (float)Math.Acos(Convert.ToDouble(Vector3.Dot(up, Vector3.Up)));

    float zAngle = (float)Math.Acos(Convert.ToDouble(Vector3.Dot(right, Vector3.Right)));

  • 9/6/2007 1:01 PM In reply to

    Re: Converting Quaternion to Euler angles

    Thanks Steve, yeah, that's more or less an implementation of what we'd been discussing. Once i get it working, I'll post the code I came up with too, if it'd be of any use to others.
  • 9/8/2007 1:54 AM In reply to

    Re: Converting Quaternion to Euler angles

    I finally got around to trying it, and after spending a little time tweaking, I got Kyle's solution working nicely. Here's the code I'm using, in case anyone else wants to mimic it. It uses two other functions in my project, so I included those here too. Sorry if they don't seem to make sense; they make sense (and work) in the context of my program. =/

    //In a 2D grid, returns the angle to a specified point from the +X axis
    public static float ArcTanAngle(float X, float Y)
    {
    if (X == 0)
    {
    if (Y == 1)
    return (float)MathHelper.PiOver2;
    else
    return (float)-MathHelper.PiOver2;
    }
    else if (X > 0)
    return (float)Math.Atan(Y / X);
    else if (X < 0)
    {
    if (Y > 0)
    return (float)Math.Atan(Y / X) + MathHelper.Pi;
    else
    return (float)Math.Atan(Y / X) - MathHelper.Pi;
    }
    else
    return 0;
    }

    //returns Euler angles that point from one point to another
    public static Vector3 AngleTo(Vector3 from, Vector3 location)
    {
    Vector3 angle = new Vector3();
    Vector3 v3 = Vector3.Normalize(location-from);
    angle.X = (float)Math.Asin(v3.Y);
    angle.Y = ArcTanAngle(-v3.Z, -v3.X);
    return angle;
    }

    //converts a Quaternion to Euler angles (X = pitch, Y = yaw, Z = roll)
    public static Vector3 QuaternionToEuler(Quaternion rotation)
    {
    Vector3 rotationaxes = new Vector3();

    Vector3 forward = Vector3.Transform(Vector3.Forward, rotation);
    Vector3 up = Vector3.Transform(Vector3.Up, rotation);
    rotationaxes = AngleTo(new Vector3(), forward);
    if (rotationaxes.X == MathHelper.PiOver2)
    {
    rotationaxes.Y = ArcTanAngle(up.Z, up.X);
    rotationaxes.Z = 0;
    }
    else if (rotationaxes.X == -MathHelper.PiOver2)
    {
    rotationaxes.Y = ArcTanAngle(-up.Z, -up.X);
    rotationaxes.Z = 0;
    }
    else
    {
    up = Vector3.Transform(up, Matrix.CreateRotationY(-rotationaxes.Y));
    up = Vector3.Transform(up, Matrix.CreateRotationX(-rotationaxes.X));
    rotationaxes.Z = ArcTanAngle(up.Y, -up.X);
    }
    return rotationaxes;
    }
  • 5/16/2008 2:04 PM In reply to

    Re: Converting Quaternion to Euler angles

    Ed, that's brilliant.

    As I note in this thread, that's a very handy little sample-ette which has allowed me to cheerfully kludge around picking up inadvertant roll during camera movement.

    Cheers muchly.
  • 5/17/2008 10:24 PM In reply to

    Re: Converting Quaternion to Euler angles

    I'm confused, why are you using a custom function (ArcTanAngle), rather than simply using Math.atan2()?

  • 5/18/2008 1:01 PM In reply to

    Re: Converting Quaternion to Euler angles

    Perhaps I didn't know such such a function existed. Looking it up on MSDN, it looks like it does the same thing. You can try substituting it if you'd like, but I used the custom function.

    Either way, Genstein, I'm really glad my code was helpful to you. I'd completely forgotten about this thread and this issue (and about programming in general, I'm afraid; haven't done any work with this in months), but I was really grateful to see that I was able to contribute. =)

  • 5/18/2008 6:56 PM In reply to

    Re: Converting Quaternion to Euler angles

    Sometimes I like figuring it out on my own as well, it feels good to know you did it on your own. Generally once I find out a method already exists I'll end up using it, because there is a 99% chance whoever created the original method did it better than I did.

    For example, you seem to be casting things to floats that are already floats, example:

    (float)Mathhelper.PiOver2

    You might be able to use reflection to take a look at exactly how they did Math.atan2(). 

     

  • 5/18/2008 7:10 PM In reply to

    Re: Converting Quaternion to Euler angles

    Sometimes I like "reinventing the wheel" just so I have a better idea of how things work internally. Once I'm confident that a premade function does exactly what I need, then I'll get into the habit of using it instead. Same case here.

    Regarding floats, I think I converted because a Vector3 consists of three floats instead of doubles.

  • 7/28/2009 4:38 PM In reply to

    Re: Converting Quaternion to Euler angles

    Hi everyone,

    The above function did not work for me, so I created my own which does work.This function was extrapolated by reading the work of Martin John Baker. All credit for this function goes to Martin John.
    http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm

    I hope this helps someone out there.
    kind regards and happy coding.
    Cathal

    1         /// <summary> 
    2         /// The function converts a Microsoft.Xna.Framework.Quaternion into a Microsoft.Xna.Framework.Vector3 
    3         /// </summary> 
    4         /// <param name="q">The Quaternion to convert</param> 
    5         /// <returns>An equivalent Vector3</returns> 
    6         /// <remarks> 
    7         /// This function was extrapolated by reading the work of Martin John Baker. All credit for this function goes to Martin John. 
    8         /// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm 
    9         /// </remarks> 
    10         public Vector3 QuaternionToEuler(Quaternion q) 
    11         { 
    12             Vector3 v = new Vector3(); 
    13  
    14             v.X = (float)Math.Atan2 
    15             ( 
    16                 2 * q.Y * q.W - 2 * q.X * q.Z,  
    17                 1 - 2*Math.Pow(q.Y, 2) - 2*Math.Pow(q.Z, 2) 
    18             ); 
    19  
    20             v.Y = (float)Math.Asin 
    21             ( 
    22                 2*q.X*q.Y + 2*q.Z*q.W 
    23             ); 
    24  
    25             v.Z = (float)Math.Atan2 
    26             ( 
    27                 2*q.X*q.W-2*q.Y*q.Z, 
    28                 1 - 2*Math.Pow(q.X, 2) - 2*Math.Pow(q.Z, 2) 
    29             ); 
    30  
    31             if(q.X*q.Y + q.Z*q.W == 0.5) 
    32             { 
    33                 v.X = (float)(2 * Math.Atan2(q.X,q.W)); 
    34                 v.Z = 0;     
    35             } 
    36  
    37             else if(q.X*q.Y + q.Z*q.W == -0.5) 
    38             { 
    39                 v.X = (float)(-2 * Math.Atan2(q.X, q.W)); 
    40                 v.Z = 0; 
    41             } 
    42  
    43             return v; 
    44         } 

  • 9/30/2009 9:21 AM In reply to

    Re: Converting Quaternion to Euler angles

    The above formula works fine with one exception, it switches Pitch with Roll.

    Quaternion q = Quaternion.CreateFromYawPitchRoll(0.15f, 0.1f, 0.05f); 
    Vector3 ypr = functions.QuaternionToEuler(q); 
    The result is that ypr = 0.15, 0.05, 0.1

    I switched them back in this version of the function:
    public Vector3 QuaternionToEuler(Quaternion q) 
            { 
                Vector3 v = Vector3.Zero; 
     
                v.X = (float)Math.Atan2  
                ( 
                    2 * q.Y * q.W - 2 * q.X * q.Z, 
                       1 - 2 * Math.Pow(q.Y, 2) - 2 * Math.Pow(q.Z, 2) 
                ); 
     
                v.Z = (float)Math.Asin 
                ( 
                    2 * q.X * q.Y + 2 * q.Z * q.W 
                ); 
     
                v.Y = (float)Math.Atan2 
                ( 
                    2 * q.X * q.W - 2 * q.Y * q.Z, 
                    1 - 2 * Math.Pow(q.X, 2) - 2 * Math.Pow(q.Z, 2) 
                ); 
     
                if (q.X * q.Y + q.Z * q.W == 0.5) 
                { 
                    v.X = (float)(2 * Math.Atan2(q.X, q.W)); 
                    v.Y = 0; 
                } 
     
                else if (q.X * q.Y + q.Z * q.W == -0.5) 
                { 
                    v.X = (float)(-2 * Math.Atan2(q.X, q.W)); 
                    v.Y = 0; 
                } 
     
                return v; 
            }  

    enjoy!
  • 12/20/2009 4:31 PM In reply to

    Re: Converting Quaternion to Euler angles

    I want to encode an orientation as (yaw, pitch, roll)
    so I can store it in a texture and use it to render a model instance in a vertex shader

    I rewrote the above code to use an epsilon instead of == 0.5 (copying the martin baker approach)

    It would be great if someone could confirm the function is OK


    public static Vector3 QuaternionToYawPitchRoll(Quaternion q) { 
     
        const float Epsilon = 0.0009765625f; 
        const float Threshold = 0.5f - Epsilon; 
     
        float yaw; 
        float pitch; 
        float roll; 
     
        float XY = q.X * q.Y; 
        float ZW = q.Z * q.W; 
     
        float TEST = XY + ZW; 
     
        if (TEST < -Threshold || TEST > Threshold) { 
     
            int sign = Math.Sign(TEST); 
     
            yaw = sign * 2 * (float)Math.Atan2(q.X, q.W); 
             
            pitch = sign * MathHelper.PiOver2; 
             
            roll = 0; 
     
        } else { 
     
            float XX = q.X * q.X; 
            float XZ = q.X * q.Z; 
            float XW = q.X * q.W; 
     
            float YY = q.Y * q.Y; 
            float YW = q.Y * q.W; 
            float YZ = q.Y * q.Z; 
     
            float ZZ = q.Z * q.Z; 
     
            yaw = (float)Math.Atan2(2 * YW - 2 * XZ, 1 - 2 * YY - 2 * ZZ); 
     
            pitch = (float)Math.Atan2(2 * XW - 2 * YZ, 1 - 2 * XX - 2 * ZZ); 
     
            roll = (float)Math.Asin(2 * TEST); 
     
        }//if 
     
        return new Vector3(yaw, pitch, roll); 
     
    }//method 
     

    Researching this simple function was complicated by three things:

    - Coordinate system in use (this uses XNA Right Hand Y-up)
    - Quaternion mapping (this uses XNA W = scalar = q0, XYZ matches coordinate system)
    - The order of application (I hope this uses Yaw, Pitch, Roll)

    none of it helped by the typos on martin bakers website

    Heading = rotation about y axis 
    Attitude = rotation about z axis 
    Bank = rotation about x axis 

    which should read:
    "Attitude = rotation about x axis"
    "Bank = rotation about z axis"

    Which is why I would like another opinion - it is quite confusing
Page 1 of 2 (26 posts) 1 2 Next > Previous Discussion Next Discussion