# DirectX Quaternion SLERP Wrong Answer?

I have some code that looks like this:

DirectX::XMVECTOR a, b, c;
a = DirectX::XMQuaternionIdentity();
b = DirectX::XMQuaternionRotationAxis(DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f), 3.1415f);
c = DirectX::XMQuaternionRotationAxis(DirectX::XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f), (3.1415f * 3.0f) / 2.0f);

DirectX::XMVECTOR slerpAB = DirectX::XMQuaternionSlerp(a, b, 0.4f);
DirectX::XMVECTOR slerpBC = DirectX::XMQuaternionSlerp(b, c, 0.85f);
DirectX::XMVECTOR slerpCA = DirectX::XMQuaternionSlerp(c, a, 1.0f);


The thing is, I'm sure that slerpBC is wrong. Here's what I'm getting:

If I understand it right, slerpBC should be 85% of the way towards a 3-quater turn around the Z axis. But when I plug that value in to Wolfram Alpha, it looks totally wrong.

Furthermore, when I run the code through my own Slerp code I get a totally different answer that looks more correct, to me.

So... What am I doing wrong?

• slerpBC starts from a 180° rotation around the Y and then goes to a 270° rotation around the Z axis – ratchet freak Nov 25 '14 at 11:44
• @ratchetfreak Right, so I would expect that at 0.85x the interpolation, I should be close to 270deg around Z, with a small rotation around Y. That's what I see in my own answer; but not the one DirectX gives me? – Xenoprimate Nov 25 '14 at 11:48
• unless it goes the other way, most slerp implementations take the shorter path – ratchet freak Nov 25 '14 at 11:49

The quaternion you find using your method is indeed correct.

However, it’s also pretty unlikely that DirectX::XMQuaternionSlerp would behave incorrectly with such trivial input.

Thus, I suspect that the thing you are doing wrong is:

• trusting what you see in the debugger while running potentially optimised code
• assuming the layout of a __mm128 would be the {W,X,Y,Z} of your quaternion (DirectX quaternions are stored as XYZW so the value you plugged into Wolfram Alpha was X + Yi + Zj + Wk anyway)

So, use XMVectorGetX(slerpBC) to get and print the X value of your quaternion instead, you’ll see whether it matches what the debugger says.

• That was exactly the problem, thank you. I was making a double error of assuming the quats were WXYZ and then trusting the debugger output! – Xenoprimate Nov 26 '14 at 10:27

By design, DirectXMath returns for XMQuaternionSlerp the same result as you'd get from the following (inefficient used only for testing) scalar code:

XMVECTOR ScalarQuatSlerp(XMVECTOR q1, XMVECTOR q2, float t)
{
// Extract the components
float q1x = XMVectorGetX(q1);
float q1y = XMVectorGetY(q1);
float q1z = XMVectorGetZ(q1);
float q1w = XMVectorGetW(q1);
float q2x = XMVectorGetX(q2);
float q2y = XMVectorGetY(q2);
float q2z = XMVectorGetZ(q2);
float q2w = XMVectorGetW(q2);
// Find the dot product
float dot = (q1x * q2x) +
(q1y * q2y) +
(q1z * q2z) +
(q1w * q2w);
// Determine the direction of the rotation.
if (dot < 0.0f) {
dot = -dot;
q2x = -q2x;
q2y = -q2y;
q2z = -q2z;
q2w = -q2w;
}
float theta = acosf(dot);
float sintheta = sinf(theta);
float scale1 = (sinf(theta*(1.0f-t)) / sintheta);
float scale2 = (sinf(theta*t) / sintheta);
// Perform the slerp.
q1x = (q1x*scale1) + (q2x*scale2);
q1y = (q1y*scale1) + (q2y*scale2);
q1z = (q1z*scale1) + (q2z*scale2);
q1w = (q1w*scale1) + (q2w*scale2);
// Convert the scalar answer to a vector
XMVECTOR r = XMVectorSet(q1x,q1y,q1z,q1w);
return r;
}


which is derived from the classic quaternion paper: Shoemake, Ken. "Animating Rotation with Quaternion Curves", Compute Graphics (SIGGRAPH 1985), Volume 19, Number 3, 1985.

You should read Jonathan Blow's The Inner Product, April 2004 article on slerp: Understanding Slerp, Then Not Using It. Basically, for most applications you shouldn't use XMQuaternionSlerp. Instead use 'nlerp' which is implemented in DirectXMath as:

XMVECTOR r = XMVectorLerp( q1, q2, t );
r = XMQuaternionNormalize( r );

• Thanks for your comments. I've also implemented a LerpAndNormalize and my output matches that of DirectX's. Also, it's super useful to see a reference implementation of slerp, so thank you very much! – Xenoprimate Nov 26 '14 at 10:28