0

I'm writing code that requires rotation of objects around any point in 3D space. I've found the methods for rotating objects by the euler angles, but they all seem to rotate around the origin.

So to rotate around any point, must I first move the coordinate system by subtracting the coordinates of the rotation point from each point in the object, do the rotation, and then move the coordinate system again?

Or are the simpler, more direct (and more computationally efficient) ways to do this?

K0ICHI
  • 145
  • 6

2 Answers2

2

A 3D rotation around an arbitrary point $(x_0, y_0, z_0)$ is described by $$\left[ \begin{matrix} x^\prime \\ y^\prime \\ z^\prime \end{matrix} \right] = \left[ \begin{matrix} X_x & Y_x & Z_x \\ X_y & Y_y & Z_y \\ X_z & Y_z & Z_z \end{matrix} \right] \left[ \begin{matrix} x - x_0 \\ y - y_0 \\ z - z_0 \end{matrix} \right] + \left[ \begin{matrix} x_0 \\ y_0 \\ z_0 \end{matrix} \right]$$ which, as OP noted, first subtracts the center point, rotates around the origin, then adds back the center point; equivalently written as $$\vec{p}^\prime = \mathbf{R} \left( \vec{p} - \vec{p}_0 \right) + \vec{p}_0$$ We can combine the two translations, saving three subtractions per point – not much, but might help in a computer program. This is because $$\vec{p}^\prime = \mathbf{R} \vec{p} + \left( \vec{p}_0 - \mathbf{R} \vec{p}_0 \right)$$ In other words, you can use the simple form, either $$\left[ \begin{matrix} x^\prime \\ y^\prime \\ z^\prime \end{matrix} \right] = \left[ \begin{matrix} X_x & Y_x & Z_x \\ X_y & Y_y & Z_y \\ X_z & Y_z & Z_z \end{matrix} \right] \left[ \begin{matrix} x \\ y \\ z \end{matrix} \right] + \left[ \begin{matrix} T_x \\ T_y \\ T_z \end{matrix} \right]$$ or, equivalently, $$\left[ \begin{matrix} x^\prime \\ y^\prime \\ z^\prime \\ 1 \end{matrix} \right] = \left[ \begin{matrix} X_x & Y_x & Z_x & T_x \\ X_y & Y_y & Z_y & T_y \\ X_z & Y_z & Z_z & T_z \\ 0 & 0 & 0 & 1 \end{matrix} \right] \left[ \begin{matrix} x \\ y \\ z \\ 1 \end{matrix} \right]$$ where $$\left[ \begin{matrix} T_x \\ T_y \\ T_z \end{matrix} \right] = \left[ \begin{matrix} x_0 \\ y_0 \\ z_0 \end{matrix} \right] - \left[ \begin{matrix} X_x & Y_x & Z_x \\ X_y & Y_y & Z_y \\ X_z & Y_z & Z_z \end{matrix} \right] \left[ \begin{matrix} x_0 \\ y_0 \\ z_0 \end{matrix} \right]$$ to apply a rotation $\mathbf{R}$ around a centerpoint $(x_0, y_0, z_0)$.

The 4×4 matrix form is particularly useful if you use SIMD, like SSE or AVX, with four-component vectors; that's one reason why many 3D libraries use it. Another is that the same form can be used for projection.

Example
  • 166
  • Thanks. Very good answer. Especially appreciate the bonus explanation of the 4x4 matrix and SIMD. Unfortunately I don't have the luxury of SIMD, but that is definitely something to remember if I port to a different processor.

    For the time being I have to implement every basic arithmetic operation for the linear algebra, and the bulk of the work is in calculating the rotation matrix itself. I should have been clearer in the questions, but I was also hoping for a method that required fewer arithmetic operations than multiplying 5 3x3 matrices. Any hope for that?

    – K0ICHI Jun 11 '20 at 13:43
  • @K0ICHI: Sure, versors aka unit quaternions. Essentially, an unit quaternion is a four-component vector $\mathbf{q} = (w, i, j, k)$ that describes a pure 3×3 rotation matrix. (It is an unit quaternion because $w^2 + i^2 + j^2 + k^2$, and if you get any rounding error, you can renormalize it to unit length.) To rotate $\mathbf{q}_1$ by $\mathbf{q}_2$ you do Hamilton product $\mathbf{q}_2 \mathbf{q}_1$, which involves 16 multiplications and 12 additions/subtractions, but you can also interpolate between orientations. [...] – Example Jun 11 '20 at 20:01
  • @K0ICHI: There is one way to convert a matrix to a quaternion and vice versa. One is sufficient to describe any orientation. There is no bias, no gimbal lock. So, you only need one matrix or one unit quaternion per object (that can have their own orientation). The conversion needs "extra" multiplications etc., but the versatility is worth the minor overhead. – Example Jun 11 '20 at 20:03
  • Thanks for another great suggestion. I was actually reading up on quaternions. Seems like they way to go! – K0ICHI Jun 12 '20 at 02:15
  • @K0ICHI: You might find this and this informative/useful. – Example Jun 12 '20 at 11:32
  • Will have a look, but I think I've understood what I need. Currently translating the math to code, and discovered a shortcut. When calculating the Hamilton product of the rotation quaternion and the position quaternion, which real part is zero, some of the terms are zero as well. So it reduces to 12 multiplications and 8 additions. – K0ICHI Jun 12 '20 at 12:17
  • @K0ICHI: Note that $(\pm1, 0, 0, 0)$ is "no change", and $(0, i, j, k)$ is a $180°$ rotation around unit axis vector $(i, j, k)$. Unit quaternions are also funky in that you can negate all four components, without affecting the orientation it represents. It is absolutely the best approach to play with them, writing real code and use them, and then maybe check some of the quaternion algebra to see if there are additional tricks and shortcuts – from experience, I can say this is easy and works well. – Example Jun 12 '20 at 15:18
0

Let $c$ be the desired rotation center. Your transformation is

$$q=R(p-c)+c$$ or $$q=Rp+c-Rc.$$

The first expression takes two vector additions. The second only one if you can precompute $c-Rc$. The gain is marginal and you can't do better.