I writing a multi-player game and am having some trouble understanding how to extrapolate a quaternion during prediction on the client side.
For example, let us say I have a quaternion q1 at time t1 and quaternion q2 at time t2 and both are known values that have happened in the passed. On my client I am trying to predict what quaternion q3 will be at time t3 prior to the server providing me the real q3.
Note: t3 > t2 > t1
My quat math is pretty lousy and i’m guessing I can’t just slerp outside the 0 - 1 range.
I hope I have explained myself clearly enough any help would be greatly appreciated
I think this can be done using the following algorithm: find the rotation rot from q1 to q2 multiplying the inverse of q1 by q2 and calculate the “extrapolation factor” dt = (t3-t1)/(t2-1). dt will be a number > 1, where the integer part means full rot rotations from q1. Apply these full rotations while decrementing dt, and when it falls below 1 use Slerp (or Lerp) to apply the last and partial rotation:
var rot = Quaternion.Inverse(q1)*q2; // rot is the rotation occurred from t1 to t2
var dt = (t3 - t1)/(t2 - t1); // dt = extrapolation factor
var q4 = q2;
while (dt > 1){
q3 = q4; // q3 is the last full rotation
q4 = rot * q4; // q4 is the next full rotation
dt -= 1;
}
q3 = Quaternion.Slerp(q3, q4, dt);
I haven’t tested this; let me know if it has any error.
EDITED: I tested this algorithm, and found a jerky behaviour at certain angles. Then I studied the case a little more and found (after some Google search) a simpler way to do this. The idea is: a Quaternion is just a rotation of some angle around an arbitrary axis - the angle and axis returned by the function ToAngleAxis. Thus, to extrapolate a quaternion, all we have to do is to get the angle-axis representation, multiply the angle by the extrapolation factor, convert it back to quaternion with AngleAxis, then combine this rotation with the first one.
var rot = q2*Quaternion.Inverse(q1); // rot is the rotation from t1 to t2
var dt = (t3 - t1)/(t2 - t1); // dt = extrapolation factor
var ang: float;
var axis: Vector3;
rot.ToAngleAxis(ang, axis); // find axis-angle representation
if (ang > 180) ang -= 360; // assume the shortest path
ang = ang * dt % 360; // multiply angle by the factor
q3 = Quaternion.AngleAxis(ang, axis) * q1; // combine with first rotation
I tested this approach, and it works perfectly - even for t3 < t2! - without the strange hickups of the previous method.