Changeset 1807


Ignore:
Timestamp:
Aug 24, 2012, 12:51:48 PM (8 years ago)
Author:
sam
Message:

math: improve slerp implementation.

Location:
trunk/src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/lol/math/vector.h

    r1799 r1807  
    935935    static Quat<T> rotate(T angle, T x, T y, T z);
    936936    static Quat<T> rotate(T angle, Vec3<T> const &v);
    937         static Quat<T> slerp(Quat<T> QuatA,Quat<T> QuatB, float const &Scalar);
    938937
    939938    /* Convert from Euler angles. The axes in fromeuler_xyx are
     
    10201019
    10211020template<typename T>
    1022 static inline Quat<T> operator /(Quat<T> x, Quat<T> const &y)
     1021static inline Quat<T> operator /(Quat<T> const &x, Quat<T> const &y)
    10231022{
    10241023    return x * re(y);
    10251024}
     1025
     1026template<typename T>
     1027extern Quat<T> slerp(Quat<T> const &qa, Quat<T> const &qb, T f);
    10261028
    10271029/*
  • trunk/src/math/vector.cpp

    r1804 r1807  
    487487}
    488488
    489 template<> quat quat::slerp(quat QuatA, quat QuatB, float const &Scalar)
    490 {
    491         float magnitude = lol::sqrt(sqlength(QuatA) * sqlength(QuatB));
    492         //btAssert(magnitude > btScalar(0));
    493 
    494         float product = lol::dot(QuatA,QuatB) / magnitude;
    495         if (product > -1.0f && product < 1.0f)
    496         {
    497                 // Take care of long angle case see http://en.wikipedia.org/wiki/Slerp
    498                 const float sign = (product < 0.0f) ? -1.0f : 1.0f;
    499 
    500                 const float theta = lol::acos(sign * product);
    501                 const float s1 = lol::sin(sign * Scalar * theta);   
    502                 const float d = 1.0f / lol::sin(theta);
    503                 const float s0 = lol::sin((1.0f - Scalar) * theta);
    504 
    505                 return quat(
    506                         (QuatA.w * s0 + QuatB.w * s1) * d,
    507                         (QuatA.x * s0 + QuatB.x * s1) * d,
    508                         (QuatA.y * s0 + QuatB.y * s1) * d,
    509                         (QuatA.z * s0 + QuatB.z * s1) * d);
    510         }
    511         else
    512         {
    513                 return QuatA;
    514         }
     489template<> quat slerp(quat const &qa, quat const &qb, float f)
     490{
     491    float const magnitude = lol::sqrt(sqlength(qa) * sqlength(qb));
     492    float const product = lol::dot(qa, qb) / magnitude;
     493
     494    /* If quaternions are equal or opposite, there is no need
     495     * to slerp anything, just return qa. */
     496    if (std::abs(product) >= 1.0f)
     497        return qa;
     498
     499    float const sign = (product < 0.0f) ? -1.0f : 1.0f;
     500    float const theta = lol::acos(sign * product);
     501    float const s1 = lol::sin(sign * f * theta);
     502    float const s0 = lol::sin((1.0f - f) * theta);
     503
     504    /* This is the same as 1/sin(theta) */
     505    float const d = 1.0f / lol::sqrt(1.f - product * product);
     506
     507    return qa * (s0 * d) + qb * (s1 * d);
    515508}
    516509
Note: See TracChangeset for help on using the changeset viewer.