Rotate vector relative to XZ plane to be relative to a new plane defined by given normal

The up reference is Y.

I have a bunch of vectors that are oriented relative to the XZ plane. I'm not sure if that makes sense, so just consider that these vectors all have positive Y values, and that these vectors are normalized.

My goal is to rotate these vectors so that they are oriented relative to a new plane, given that plane's normal.

This image may help: I want to take each of the orange vectors, and apply a rotation to them so that they lie on the plane segment whose edges have green lines attached to it, this plane is defined by a blue normal.

Let $v$ be an orange vector to rotate, whose length is 1, and whose y value is positive. Let $n$ be a blue surface normal, whose length is 1, and whose y value is positive.

Currently I do this by finding an axis and angle to rotate by, where the axis is $u = n \times \{0,1,0\}$, and the angle is $\theta = acos(\{0,1,0\} \cdot n)$.

Then I form an axis-angle rotation matrix, and multiply this matrix by $v$ to get the desired rotated vector.

The problem with this is that it is slow, so I need a faster way.

I thought that I might be able to form a rotation matrix by finding the tangent, binormal and having the given blue normal vector $n$.

So I tried this:

Tangent $t = n \times \{1,0,0\}$.

Binormal $b = t \times n$.

Then I normalize $t$ and $b$ and put them in a matrix like so:

$R = \begin{array}{ccc} t_x & b_x & n_x \\ t_y & b_y & n_y \\ t_z & b_z & n_z \end{array}$

Then I multiply the rotation matrix $R$ by $v$, but this doesn't rotate $v$ onto the plane as desired.

Is there a fast way to find the rotation matrix to rotate $v$ onto the plane defined by $n$? Does my tangent/normal/binormal matrix idea work, but I'm just making a small mistake, like calculating the binormal wrong?

• P.S. Sorry for making this simple question so long. I'm just trying to be clear. Please let me know if anything is unclear. – TheBigO Apr 25 '11 at 11:01

The problem with your "binormal" idea is that it uses a different rotation axis than the angle/axis approach. You want a rotation matrix that maps $z = (0, 0, 1)^T$ to $n$ and leaves $t$ alone. To build this matrix, you need a third correspondence, say from $a = t \times z$ to $b = t \times n$. Set up two matrices (defined by their columns) $A := (z, t, a)$ and $B := (n, t, b)$. The rotation matrix you are looking for is given by $R = B A^{-1} = B A^T$. You can multiply this out explicitly, but this is probably as efficient as it gets.

• Finally, thank you Andreas! – TheBigO May 25 '11 at 21:16

The simplest solution should be to combine two rotations along the axes. You are trying to find a rotation that brings the vector $(0,1,0)$ to $n$. Considering that rotation matrices along the axes are of the form :

$\begin{pmatrix} a & \sqrt{1-a^2} & 0 \\ -\sqrt{1-a^2} & a & 0 \\ 0 & 0 & 1\\ \end{pmatrix}$

You can solve a system of equations and find a rotation around the $z$ axis and a rotation around the $y$ axis that do what you need. If you combine both of the following rotations :

$\begin{pmatrix} \frac{n_1}{\sqrt{1-n_2^2}} & 0 & \sqrt{\frac{1-n_2^2-n_1^2}{1-n_2^2}} \\ 0 & 1 & 0 \\ -\sqrt{\frac{1-n_2^2-n_1^2}{1-n_2^2}} & 0 & \frac{n_1}{\sqrt{1-n_2^2}}\\ \end{pmatrix} \begin{pmatrix} n_2 & \sqrt{1-n_2^2} & 0 \\ -\sqrt{1-n_2^2} & n_2 & 0 \\ 0 & 0 & 1\\ \end{pmatrix}$

You get a rotation that does what you need, provided that $n=(n_1,n_2,n_3)$ is normalized.

• How is this more efficient than using the axis-angle rotation matrix as described in the question? If anything, it seems less efficient. I don't think there is any significantly more efficient way of doing this than the one described in the question (apart from making explicit use of the fact that there a number of zero entries). – joriki Apr 26 '11 at 5:17
• I thought it should be more efficient since it doesn't use inverse trigonometric and trigonometric functions? Square roots and matrix multiplication should be faster to compute, right? – Vhailor Apr 26 '11 at 16:24
• Well, I considered using this, but I knew there was a basis matrix way of doing it (not sure if that's a good way to describe it), which Andreas has now explained. You have a few inverse square roots in there, which can be much faster to approximate (using newton-raphson approximation, wikipedia Inverse Square Root) than a regular square root, and much of these calculations are repeated, which means that there is less work to do here than it might look like. That said, I doubt it is much faster than the axis-angle rotation matrix method that I was using, if it's faster at all. – TheBigO May 25 '11 at 21:25
• Finding cos(x) is not necessarily slower than sqrt(x) -- it depends. In any case Andreas method is quite fast as it's only a handful of multiplications and additions. – TheBigO May 25 '11 at 21:26
• When I posted this question a month ago, I was thinking that this isn't stackoverflow, so I didn't want to critisize this answer because there's no reason to expect software implementation details to be well known on Math.SE. Anyways +1 because this answer was ultimately helpful to my cause :) – TheBigO May 25 '11 at 21:29