I'm trying to transform the vector (1, 0, 0) by an orientation unit quaternion, which in XNA should be:

Vector3 v = Vector3.Transform(Vector3.Right, Orientation);

But this results in the Z value reversed from its expected value—for example, transforming Vector3.Right by Orientation (0.6532815, -0.270598, 0.270598, 0.6532815) results in the vector (0, 0.7071, -0.7071) when it should result in the vector (0, 0.7071, 0.7071).

I found another implementation here:

Quaternion o = Orientation;
Vector3 oV = new Vector3(o.X, o.Y, o.Z);
Vector3 v = 2 * Vector3.Cross(oV, Vector3.Right);
v = Vector3.Right + o.W * v + Vector3.Cross(oV, v);

But that results in the same problem. Reversing the Z value is trivial, but I'm worried that if I don't find a solution to this now the problem will manifest some other way down the road. Especially since, up until now, I thought I was playing by XNA's rules in my game engine (same coordinate system, same handedness).

For reference, this code I wrote does produce the expected result in my engine:

Vector3 v;
Quaternion o = OrientationGlobal;
double y = Math.Atan2(2 * (o.W * o.Z + o.X * o.Y), 1 - 2 * (o.Z * o.Z + o.Y * o.Y)); // yaw about global Z axis
v.Z = MathHelper.Clamp(2 * (o.W * o.Y - o.Z * o.X), -1, 1);
double m = Math.Sqrt(1 - v.Z * v.Z);
v.X = (float)(m * Math.Cos(y));
v.Y = (float)(m * Math.Sin(y));

What am I missing?

  • \$\begingroup\$ You are not showing the actual values for the vectors and quaternions you are using and obtaining. This would help. \$\endgroup\$ Apr 12, 2016 at 1:04
  • \$\begingroup\$ @samhocevar Okay, I added an example. Like I said, the input vector is always (1, 0, 0) and the input quaternion is an arbitrary unit quaternion. The output vector's Z value is always reversed from what I expect. \$\endgroup\$
    – user79835
    Apr 12, 2016 at 3:24
  • \$\begingroup\$ It sounds like the handedness of your output coordinate system is opposite that of the code that's generating the quaternion. \$\endgroup\$
    – DMGregory
    Apr 12, 2016 at 3:37
  • \$\begingroup\$ Transforming vector (1,0,0) by quaternion (w=0.6532815, x=-0.270598, y=0.270598, z=0.6532815) does resut in (0, 0.7071, -0.7071). Your “expected result” seems wrong to me. \$\endgroup\$ Apr 12, 2016 at 23:11

2 Answers 2


Both XNA and Fabian Giesen’s implementation behave correctly. Transforming vector (1, 0, 0) by quaternion (w=0.6532815, x=-0.270598, y=0.270598, z=0.6532815) does resut in (0, 0.7071, -0.7071). It also does in Unreal Engine, in my own quaternion implementation, as well as in Wolfram Alpha.

Wolfram Alpha also gives the 3×3 matrix equivalent of the quaternion. You can see that multiplying this matrix by (1, 0, 0) will also result in (0, 0.707107, -0.707107) since it’s trivially the first column of the matrix:

|  0         -1  0        |
|  0.707107   0  0.707107 |
| -0.707107   0  0.707107 |

There is most certainly a bug in your code above, since every other implementation basically disagrees with it, but it’s hard to understand where, as I have no idea how you derived the formulas. But the use of atan2 immediately followed by sin and cos indicates it was probably just some test code so I suggest you just throw it away and trust the XNA implementation.

Ultimately, the problem probably comes from how you build your quaternion. I’d have a look there.

  • \$\begingroup\$ Yep, my code was test code to see if I'd arrive at my expected result using terms I intuitively understand (the output vector is the direction an object is facing after Tait-Bryan yaw and pitch have been applied, and I'm fairly sure my formulas for yaw and pitch are correct because I successfully use them elsewhere in the engine). I'll try to find whatever bug is causing this. \$\endgroup\$
    – user79835
    Apr 13, 2016 at 15:04

For posterity...it ended up being a simple handedness issue, but only around the Y (pitch) axis. I had it stuck in my head that positive pitch increases Z and negative pitch decreases Z, which isn't true in a right-hand system. Lesson learned!


You must log in to answer this question.