Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficient way to calculate a 3x3 rotation matrix from the rotation defined by two 3D Vectors

Tags:

math

matrix

While I've found 2 solutions to this, I was curious if there is well known method to perform this operation since it seems a fairly common task.

Here are the 2 obvious methods psudo-code...

Axis Angle

This is quite logical, but calls sin twice and cos once (in the angle calculation and axis angle to matrix conversion).

Matrix3x3 rotation_between_vectors_to_matrix(const Vector v1, const Vector v2)
{
    angle = v1.angle(v2);
    axis  = v1.cross(v2);

    /* maths for this is well known */
    Matrix3x3 matrix = axis_angle_to_matrix(axis, angle);

    return matrix;
}

Edit: The most straightforward function is a quite slow, however as has been pointed out in the replies here: calculating the angle can be avoided by getting angle_sin and angle_cos, from the axis length and v1,v2 dot product respectively.

Difference between two matrices

Here's another method I found which constructs two 3x3 matrices from the vectors and returns the difference.

However this is slower then axis/angle calculation which can be optimized (mentioned above).

Note. this assumes both vectors are normalized, matrix is column-major (OpenGL).

Matrix3x3 rotation_between_vectors_to_matrix(const Vector v1, const Vector v2)
{
    Matrix3x3 m1, m2;

    axis = v1.cross(v2);
    axis.normalize();

    /* construct 2 matrices */
    m1[0] = v1;
    m2[0] = v2;

    m1[1] = axis;
    m2[1] = axis;

    m1[2] = m1[1].cross(m1[0]);
    m2[2] = m2[1].cross(m2[0]);

    /* calculate the difference between m1 and m2 */
    m1.transpose();

    Matrix3x3 matrix = m2 * m1;

    return matrix;
}

Are there better ways to perform this calculation?

Edit: The purpose of this question is NOT to micro-optimize and benchmark each method. Instead - I was curious if there is some totally different and superior method which I didn't know about.


Note: I purposefully left out checks for the degenerate case for co-linear vectors (where the axis is zero length), to keep the examples simple.

like image 891
ideasman42 Avatar asked Apr 19 '14 06:04

ideasman42


People also ask

How do I find the rotation between 2 vectors?

First step, you want to find the angle between the two vectors using the dot product. Next, to find the axis of rotation, use the cross product. Knowing that the cross product will yield a vector perpendicular to both u and v , crossing them in either order will give an appropriate axis.

How do you find the rotation matrix between two rotation matrices?

Using rotation matrices¶ The distance between rotations represented by rotation matrices P and Q is the angle of the difference rotation represented by the rotation matrix R = P Q ∗ .

How do you find the angle between two vectors in 3D?

To calculate the angle between two vectors in a 3D space: Find the dot product of the vectors. Divide the dot product by the magnitude of the first vector. Divide the resultant by the magnitude of the second vector.


1 Answers

Both the methods you've posted can be optimised.

Method 1

Instead of using acos to find the angle between the two vectors, a better thing to do is to avoid finding the angle at all. How? The axis-angle formula by Rodrigues requires only sin θ, cos θ and 1 - cos θ, so finding the actual angle is redundant.

We know that v1 and v2 are unit vectors; v1 · v2 = |v1| |v2| cos θ since |v1| = |v2| = 1, v1 · v2 directly gives us cos θ, finding 1 - cos θ isn't costly. v1 × v2 = |v1| |v2| sin θ n = sin θ n, where n is a unit vector perpendicular to v1 and v2, finding |v1 × v2| the magnitude of the cross product would directly give sin θ.

Now that we've sin θ and cos θ, we can directly form the rotation matrix by using Rodrigues forumla; here's a simple implementation (though page claims to use Quaternion math, it's the Axis-Angle to Matrix conversion formula).

Method 2

After you've constructed two orthonormal frames as matrices, you can avoid the second transpose you do. Here's the proof.

Say A and B be the two matrices, since you want to rotate from A to B we need some matrix X which when multiplied with A will give B:

XA = B

X = BA⁻¹

This is all you need; when you pre-multiply X to A you'd get B. However, what you find is Y

Y = AB⁻¹

YB = A

Then you transpose Y to get Y⁻¹ i.e.

Y⁻¹YB = Y⁻¹A

B = Y⁻¹A

Instead of doing two inverses (transpose here), you can just do the above method which involves only one transpose.

I'd still say that without benchmarking the methods in their optimized forms, we cannot say method 2 is faster than method 1. So I'd really urge you to benchmark between the two methods (with some non-trivial load) and then draw a conclusion.

like image 181
legends2k Avatar answered Oct 16 '22 17:10

legends2k