Simple MATLAB slerp
Alec Jacobson
April 12, 2010
Interpolating between two vectors can catch you off guard. If you just linearly interpolate (x,y,z) values you could end up with a vanishing interpolated vector. Just imagine interpolating a 2-D vector from [-1,0] to [1,0]. Halfway you've got [0,0].
One way to do this a little better is to interpolate a rotation between the vectors. The natural path to take is the shortest one which happens to also be the shortest path (of two unit vectors) of their respect points along the unit sphere. This is called spherical linear interpolation or slerp.
There's more complicated ways to do this but in MATLAB I can simply do:
function [c] = slerp(a,b,t)
angle = acos( dot(a,b) );
% easy degenerate case
if(0==angle)
c = a;
% hard case
elseif(pi==angle)
error('SLERP: angle between vectors cannot be exactly PI...');
else
c = (sin((1.0-t)*angle)/sin(angle))*a + (sin(t*angle)/sin(angle))*b;
end
end
Note: that slerping is not well defined for opposite parallel vectors. This makes sense geometrically because their respective points on the unit sphere have infinitely many, all equally minimal paths between them. E.g. the north pole has infinitely many shortest paths along the earth to the south pole.
In the end, I lerp the magnitudes of the two vectors then use that to scale the slerp of their unit vectors:
c = ( (1.0-t) * norm(a) + t* norm(b) ) * slerp( a./norm(a) , b./norm(b) , t);
where t is your interpolation parameter.
Slightly more efficiently:
mag_a = norm(a); mag_b = norm(b); c = ((1.0-t)*mag_a + t*mag_b) * slerp(a./mag_a,b./mag_b,t);
Note: Careful using norm
it is not vectorized as you might think. I.e. it doesn't return a row vector of scalars if you pass it a list of vectors (instead the matrix norm of that list treated as a matrix).