10
votes

I have two vectors describing rotations; a start rotation A and a target rotation B. How would I best go about interpolating A by a factor F to approach B?

Using a simple lerp on the vectors fails to work when more than one dimension needs to be interpolated (i.e. produces undesirable rotations). Maybe building quaternions from the rotation vectors and using slerp is the way to go. But how, then, could I extract a vector describing the new rotation from the resulting quaternion?

Thanks in advance.

4
Can you explain a bit better why SLERP doesn't work for you? What do you mean by interpolating more than one dimension, I believe it just starts at one point (vector A) and ends in another (vector B) making the shortest rotation around the origin. - catchmeifyoutry
By more than one dimension I mean more than one axis, e.g. a rotation around X and Y at the same time, as opposed to just rotating around a single axis. And this is when LERP fails. - uhuu
Fundamentally, that doesn't make a lot of sense, as every rotation around however many axes is equivalent to a rotation about some single other axis. So there is really no reason why linear interpolation wouldn't work in all cases. - Joren

4 Answers

9
votes

Since I don't seem to understand your question, here is a little SLERP implementation in python using numpy. I plotted the results using matplotlib (v.99 for Axes3D). I don't know if you can use python, but does look like your SLERP implementation? It seems to me to give fine results ...

from numpy import *
from numpy.linalg import norm

def slerp(p0, p1, t):
        omega = arccos(dot(p0/norm(p0), p1/norm(p1)))
        so = sin(omega)
        return sin((1.0-t)*omega) / so * p0 + sin(t*omega)/so * p1


# test code
if __name__ == '__main__':
    pA = array([-2.0, 0.0, 2.0])
    pB = array([0.0, 2.0, -2.0])

    ps = array([slerp(pA, pB, t) for t in arange(0.0, 1.0, 0.01)])

    from pylab import *
    from mpl_toolkits.mplot3d import Axes3D
    f = figure()
    ax = Axes3D(f)
    ax.plot3D(ps[:,0], ps[:,1], ps[:,2], '.')
    show()
4
votes

A simple LERP (and renormalizing) only works fine when the vectors are very close together, but will result in unwanted results when the vectors are further apart.

There are two options:

Simple cross-products:

Determine the axis n that is orthogonal to both A and B using a cross product (take care when the vectors are aligned) and calculate the angle a between A and B using a dot product. Now you can simply approach B by letting a go from 0 to a (this will be aNew and applying the rotation of aNew about axis n on A.

Quaternions:

Calculate the quaternion q that moves A to B, and interpolate q with the identity quaternion I using SLERP. The resulting quaternion qNew can then be applied on A.

2
votes

Well, your slerp approach would work and is probably computationally most efficient (even though it's a bit tough to understand). To get back from the quaternions to the vector, you'll need to use a set of formulas you can find here.

There's also a bit of relevant code here, although I don't know if it corresponds to the way you have your data represented.

1
votes

If you have decided to go with Quaternions (which will slerp very nicely), see my answer here on resources for implementing Quaternions: Rotating in OpenGL relative to the viewport

You should find plenty of examples in the links in that post.