} // End of Slerp() //------------------------------------------------------------------------------- // @ ApproxSlerp() //------------------------------------------------------------------------------- // Approximate spherical linear interpolation of two quaternions // Based on "Hacking Quaternions", Jonathan Blow, Game Developer, March 2002. // See Game Developer, February 2004 for an alternate method. //------------------------------------------------------------------------------- public IvQuat ApproxSlerp(ref IvQuat start, ref IvQuat end, float t) { float cosTheta = start.Dot(end); // correct time by using cosine of angle between quaternions float factor = 1.0f - 0.7878088f * cosTheta; float k = 0.5069269f; factor *= factor; k *= factor; float b = 2 * k; float c = -3 * k; float d = 1 + k; t = t * (b * t + c) + d; // initialize result IvQuat result = t * end; // if "angle" between quaternions is less than 90 degrees if (cosTheta >= ML.Util.kEpsilon) { // use standard interpolation result += (1.0f - t) * start; } else { // otherwise, take the shorter path result += (t - 1.0f) * start; } return(result); } // End of ApproxSlerp()
} // End of Lerp() //------------------------------------------------------------------------------- // @ Slerp() //------------------------------------------------------------------------------- // Spherical linearly interpolate two quaternions // This will always take the shorter path between them //------------------------------------------------------------------------------- public IvQuat Slerp(ref IvQuat start, ref IvQuat end, float t) { // get cosine of "angle" between quaternions float cosTheta = start.Dot(end); float startInterp, endInterp; // if "angle" between quaternions is less than 90 degrees if (cosTheta >= ML.Util.kEpsilon) { // if angle is greater than zero if ((1.0f - cosTheta) > ML.Util.kEpsilon) { // use standard slerp float theta = Mathf.Acos(cosTheta); float recipSinTheta = 1.0f / Mathf.Sin(theta); startInterp = Mathf.Sin((1.0f - t) * theta) * recipSinTheta; endInterp = Mathf.Sin(t * theta) * recipSinTheta; } // angle is close to zero else { // use linear interpolation startInterp = 1.0f - t; endInterp = t; } } // otherwise, take the shorter route else { // if angle is less than 180 degrees if ((1.0f + cosTheta) > ML.Util.kEpsilon) { // use slerp w/negation of start quaternion float theta = Mathf.Acos(-cosTheta); float recipSinTheta = 1.0f / Mathf.Sin(theta); startInterp = Mathf.Sin((t - 1.0f) * theta) * recipSinTheta; endInterp = Mathf.Sin(t * theta) * recipSinTheta; } // angle is close to 180 degrees else { // use lerp w/negation of start quaternion startInterp = t - 1.0f; endInterp = t; } } return(startInterp * start + endInterp * end); } // End of Slerp()
} // End of IvQuat::Rotate() //------------------------------------------------------------------------------- // @ Lerp() //------------------------------------------------------------------------------- // Linearly interpolate two quaternions // This will always take the shorter path between them //------------------------------------------------------------------------------- public IvQuat Lerp(ref IvQuat start, ref IvQuat end, float t) { // get cos of "angle" between quaternions float cosTheta = start.Dot(end); // initialize result IvQuat result = t * end; // if "angle" between quaternions is less than 90 degrees if (cosTheta >= ML.Util.kEpsilon) { // use standard interpolation result += (1.0f - t) * start; } else { // otherwise, take the shorter path result += (t - 1.0f) * start; } return(result); } // End of Lerp()