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: Applying orange vectors to a surface defined by a blue normal.

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?

  • $\begingroup$ 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. $\endgroup$ – 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.

  • $\begingroup$ Finally, thank you Andreas! $\endgroup$ – 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.

  • $\begingroup$ 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). $\endgroup$ – joriki Apr 26 '11 at 5:17
  • $\begingroup$ 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? $\endgroup$ – Vhailor Apr 26 '11 at 16:24
  • $\begingroup$ 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. $\endgroup$ – TheBigO May 25 '11 at 21:25
  • $\begingroup$ 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. $\endgroup$ – TheBigO May 25 '11 at 21:26
  • $\begingroup$ 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 :) $\endgroup$ – TheBigO May 25 '11 at 21:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.