Find the progress (0-1) of a Quaternion between it's start rotation and target rotation

I’ve been stuck on this problem all day. I want to create a method that can calculate the progress of a Quaternion from it’s start rotation and target rotation.

  • A value of 0 would represent the Quaternion at it’s start rotation.
  • A value of 0.5 would represent the Quaternion at a rotation half way between the start and target rotation.
  • A value of 1 would represent the Quaternion at it’s target rotation.

Here’s a solution I tried but it doesn’t fully work:

public static float GetQuaternionProgress(Quaternion current, Quaternion target, Quaternion start)
{
    float angleOriginalToTarget = Quaternion.Angle(start, target);
    float angleCurrentToTarget = Quaternion.Angle(current, target);
            
    if (Mathf.Approximately(angleOriginalToTarget, 0f))
    {
        return Mathf.Approximately(angleCurrentToTarget, 0f) ? 1f : 0f;
    }
            
    float progress = 1f - (angleCurrentToTarget / angleOriginalToTarget);
    return Mathf.Clamp01(progress);
}

I did try calculating the progress with the Euler angles but the progress value was all over the place and it didn’t work.

Here’s an example of the same idea, but for a Vector3:

public static float GetVector3Progress(Vector3 current, Vector3 target, Vector3 original)
{
    Vector3 totalRange = target - original;

    if (Mathf.Approximately(totalRange.magnitude, 0))
    {
        return 1f; 
    }
            
    float currentProgress = Vector3.Dot(current - original, totalRange) / totalRange.magnitude;
    float normalizedValue = currentProgress / totalRange.magnitude;
    return Mathf.Clamp01(normalizedValue);
}

The thing you need to google for here is Quaternion Inverse Lerp (or Inverse Slerp).

Should be able to find some results for that, for example this

1 Like

Thanks for the pointer!

Here’s the solution for finding the progress of a Quaternion:

public static float GetQuaternionProgress(Quaternion current, Quaternion target, Quaternion original)
{
    float angleAtoB = Quaternion.Angle(original, target);
    float angleAtoValue = Quaternion.Angle(original, current);
    
    if (Mathf.Approximately(angleAtoB, 0f))
    {
        return Mathf.Approximately(angleAtoValue, 0f) ? 0f : 1f;
    }

    return Mathf.Clamp01(angleAtoValue / angleAtoB);
}