VOID Quaternion::slerp( F32 t, const Quaternion& from, const Quaternion& to) { const F32 epsilon = 0.00001f; F32 omega, cosomega, sinomega, scale_from, scale_to ; Quaternion quatTo(to); // this is a dot product cosomega = from._v[0]*to._v[0] + from._v[1]*to._v[1] + from._v[2]*to._v[2] + from._v[3]*to._v[3]; if ( cosomega < 0.0f ) { cosomega = -cosomega; quatTo = -to; } if( (1.0f - cosomega) > epsilon ) { omega= ::acos(cosomega) ; // 0 <= omega <= Pi (see man acos) sinomega = ::sin(omega) ; // this sinomega should always be +ve so // could try sinomega=sqrtf(1-cosomega*cosomega) to avoid a sin()? scale_from = ::sin((1.0f-t)*omega)/sinomega ; scale_to = ::sin(t*omega)/sinomega ; } else { // The ends of the vectors are very close // we can use simple linear interpolation - no need // to worry about the "spherical" interpolation scale_from = 1.0f - t ; scale_to = t ; } *this = (from*scale_from) + (quatTo*scale_to); }
/// Spherical Linear Interpolation /// As t goes from 0 to 1, the Quat object goes from "from" to "to" /// Reference: Shoemake at SIGGRAPH 89 /// See also /// http://www.gamasutra.com/features/programming/19980703/quaternions_01.htm void ofQuaternion::slerp( float t, const ofQuaternion& from, const ofQuaternion& to ) { const double epsilon = 0.00001; double omega, cosomega, sinomega, scale_from, scale_to ; ofQuaternion quatTo(to); // this is a dot product cosomega = from.asVec4().dot(to.asVec4()); if ( cosomega < 0.0 ) { cosomega = -cosomega; quatTo = -to; } if ( (1.0 - cosomega) > epsilon ) { omega = acos(cosomega) ; // 0 <= omega <= Pi (see man acos) sinomega = sin(omega) ; // this sinomega should always be +ve so // could try sinomega=sqrt(1-cosomega*cosomega) to avoid a sin()? scale_from = sin((1.0 - t) * omega) / sinomega ; scale_to = sin(t * omega) / sinomega ; } else { /* -------------------------------------------------- The ends of the vectors are very close we can use simple linear interpolation - no need to worry about the "spherical" interpolation -------------------------------------------------- */ scale_from = 1.0 - t ; scale_to = t ; } *this = (from * scale_from) + (quatTo * scale_to); // so that we get a Vec4 }