Efficient way to calculate a 3x3 rotation matrix from the rotation defined by two 3D Vectors
math, matrix
Solution
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.
Problem
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.