Search code examples
c++opengl3dquaternions

Quaternion slerp with shortest path not working


My slerp routine is below. From what I've read, the check against > 0 should handle it so it always takes the shortest path. But it never does. In the case where I cross a "pole", the quaternion flips out and produces angles with NAN values.

quat quat::slerp(quat dest, float t)
{
  const quat &from = *this;
  static const double epsilon = 0.0001;
  double theta, cosTheta, sinTheta;
  double p, q;

  cosTheta = from.x*dest.x + from.y*dest.y + from.z*dest.z + from.w*dest.w;

  if(cosTheta < 0.0)
  {
    dest = { -from.x, -from.y, -from.z, -from.w };
    cosTheta = -cosTheta;
  }

  if((1.0-fabs(cosTheta)) > epsilon)
  {
    theta = acos(cosTheta);
    sinTheta = sin(theta);
    q = sin((1-t) * theta) / sinTheta;
    p = sin(t*theta) / sinTheta;
  }
  else
  {
    q = 1-t;
    p = t;
  }

  quat qo;
  qo.w = (float)((q * from.w) + (p * dest.w));
  qo.x = (float)((q * from.x) + (p * dest.x));
  qo.y = (float)((q * from.y) + (p * dest.y));
  qo.z = (float)((q * from.z) + (p * dest.z));

  return qo;
}

Solution

  • Maybe there are other bugs as well, but this line certainly has one:

    dest = { -from.x, -from.y, -from.z, -from.w };
    

    It overwrites dest with -from, which is not correct. It should be:

    dest = { -dest.x, -dest.y, -dest.z, -dest.w };