<blockquote>
  <p>My question is, how should I (...) rotate normals of my mesh.</p>
</blockquote>

<p>Normals are rotated the same way as the rest of your mesh/point cloud. But make sure that you use a "pure rotation matrix" for this (no scaling, no translation). Since rotations preserve lengths, you do not need to renormalize your normals (usually - floating-point errors might accumulate).</p>

<p>This sentence of you</p>

<blockquote>
  <p>Note that this rotation also needs to keep object in unit cube, where it was before running this code.</p>
</blockquote>

<p>lets me guess, that you are actually asking how to rotate an object and its normals and not just the normals. In python, you can use the packages SciPy and NumPy for that.</p>

<p>The Rotation package (<a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.transform.Rotation.html" rel="nofollow noreferrer">documentation</a>) of SciPy helps you to generate an arbitrary rotation matrix. Then you can use NumPys <code>matmul</code> function to rotate your points and normals.</p>

<p>Here is a short example script that rotates a single point 20 degrees around the z axis:</p>

<pre><code>from scipy.spatial.transform import Rotation as Rot
import numpy as np

p = np.array([1, 1, 0]).transpose()
rot_mat = Rot.from_euler(seq="z", angles=20, degrees=True).as_matrix()

p_r = np.matmul(rot_mat, p)

print(p)
print(p_r)
print(np.linalg.norm(p))
print(np.linalg.norm(p_r))
</code></pre>

<p>output:</p>

<pre><code>[1 1 0]
[0.59767248 1.28171276 0.        ]
1.4142135623730951
1.414213562373095
</code></pre>

<blockquote>
  <p><strong>Info:</strong> Depending on your SciPy version you might need to replace <code>as_matrix</code> with <code>as_dcm</code></p>
</blockquote>

<p>As you can see, apart from some minor floating-point error, the length (last 2 outputs) did not change. Furthermore, I chose the example point, so that it gets outside the unit cube. To address this problem, you need to find the maximum absolute value inside the transformed data. You can use <code>amax</code> and <code>amin</code> to get the maximum and minimum value (<a href="https://stackoverflow.com/questions/55284090/how-to-find-max-value-in-2d-array-with-index">see also here</a>) if you put all your coordinates into one large 2d array (a matrix). Then compare the absolute values of the <code>amax</code> and <code>amin</code> results and pick the larger one. Divide all your coordinates (not the normals!) by this value, to scale your model back into the unit cube. Alternatively, you can create a uniform scaling matrix</p>

<p><span class="math-container">$$
\begin{bmatrix}
s&amp;0&amp;0\\
0&amp;s&amp;0\\
0&amp;0&amp;s
\end{bmatrix}
$$</span></p>

<p>with <span class="math-container">$s$</span> being the reciprocal of the maximum absolute value. Multiply this matrix with all points.</p>

<p>To sum it up:</p>

<ul>
<li>calculate the rotation matrix with SciPy</li>
<li>Multiply the rotation matrix with all points and normals</li>
<li>find the maximum absolute value in the rotated data</li>
<li>scale your coordinates with the found maximum value</li>
</ul>

<p><strong>Remark:</strong> If you put your points and normals into 2 matrices, you can apply the rotations and scaling matrices without a loop, which makes it much faster.</p>

CC BY-SA 4.0
2020-05-04T01:26:52.767Z
But if the model is centered around the center (0,0,0) in a unit cube, is there really a need for rescaling points back to the unit cube?  Moreover, can I use the same rotation matrix for normals as I used for points?
GreatDuke
CC BY-SA 4.0
2020-05-04T11:32:30.577Z
also, I don't like your approach by scaling by maximum value across all axises (x,y,z), since it degrades pointcloud objects significantly. Say you have a pencil like object, if you scale it by it's maximum value, which is surely going to be along the pencil length, and divide both it's width and height by the same value, you will get something that looks more like a small radius stick than the pencil.
GreatDuke
CC BY-SA 4.0
2020-05-04T12:09:31.033Z
Question 1: Depends on your model. But take the unit cube itself as an example. If you rotate it by any angle that isn't a multiple of 90 degrees, The corners will end up outside the unit cube. To visualize it, take two dice and put them on top of each other so that they are aligned. Now rotate the upper one by 45 degrees. See the problem? Only if all your points are initially inside the unit sphere, you can be sure that no point will end up outside the unit cube after an arbitrary rotation.
wychmaster
CC BY-SA 4.0
2020-05-04T12:11:57.177Z
Also, why scaling by some value, it's rotation and should be shape and length preserving, wouldn't shifting/translation be correct way of bringing object back to the unit cube?
GreatDuke
CC BY-SA 4.0
2020-05-04T12:13:05.083Z
Question 2: Yes, actually you HAVE to, otherwise you get wrong normals. A quote from my answer: "Normals are rotated the same way as the rest of your mesh/point cloud."
wychmaster
CC BY-SA 4.0
2020-05-04T12:20:22.367Z
Regarding your second comment: If you use the scaling I described, it just shrinks the model. So you will just get a smaller pencil, but the ratio between thickness and length is preserved. Maybe you should read a little bit more about the basic operations that are used in computer graphics: Scaling, rotation, translation. See [this tutorial](https://learnopengl.com/Getting-started/Transformations).
wychmaster
CC BY-SA 4.0
2020-05-04T12:25:51.250Z
Question of your 3. comment: Translation MIGHT work, but in case of the rotated unit cube (angles != 90° * N)  as a model, there is no way to translate it into the unrotated unit cube. The only way to fit it without scaling is to rotate it back.
wychmaster
CC BY-SA 4.0
2020-05-04T14:40:24.130Z
Is centroid (central point of the pointcloud) preserved after rotation translation? Could I by just shifting centroid to 0,0,0 bring back my object to unit cube?
GreatDuke
CC BY-SA 4.0
2020-05-03T09:29:27.763Z
2020-05-03T09:29:27.763Z
wychmaster
<p>I am doing some project on object reconstruction and I need to rotate an object in PyTorch during the training to make sure I am augmenting the data properly. My data consists of points and it's normals. My question is, how should I (or should I train them at all) rotate the normals of my mesh. Note that this rotation also needs to keep the object inside the unit cube, where it was before the transformation. </p>

<3d><mesh>
Rotation of meshes in PyTorch
GreatDuke
# Rotation of meshes in PyTorch

(Asked by: username_0 on 2020-05-02)

I am doing some project on object reconstruction and I need to rotate an object in PyTorch during the training to make sure I am augmenting the data properly. My data consists of points and it's normals. My question is, how should I (or should I train them at all) rotate the normals of my mesh. Note that this rotation also needs to keep the object inside the unit cube, where it was before the transformation.

**Tags:** 3d, mesh


---

## 1 answers

### Answer by username_1 on 2020-05-03. Score: 1

> My question is, how should I (...) rotate normals of my mesh.

Normals are rotated the same way as the rest of your mesh/point cloud. But make sure that you use a "pure rotation matrix" for this (no scaling, no translation). Since rotations preserve lengths, you do not need to renormalize your normals (usually - floating-point errors might accumulate).

This sentence of you

> Note that this rotation also needs to keep object in unit cube, where it was before running this code.

lets me guess, that you are actually asking how to rotate an object and its normals and not just the normals. In python, you can use the packages SciPy and NumPy for that.

The Rotation package ([documentation](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.transform.Rotation.html)) of SciPy helps you to generate an arbitrary rotation matrix. Then you can use NumPys `matmul` function to rotate your points and normals.

Here is a short example script that rotates a single point 20 degrees around the z axis:

```
from scipy.spatial.transform import Rotation as Rot
import numpy as np

p = np.array([1, 1, 0]).transpose()
rot_mat = Rot.from_euler(seq="z", angles=20, degrees=True).as_matrix()

p_r = np.matmul(rot_mat, p)

print(p)
print(p_r)
print(np.linalg.norm(p))
print(np.linalg.norm(p_r))

```

output:

```
[1 1 0]
[0.59767248 1.28171276 0.        ]
1.4142135623730951
1.414213562373095

```

> **Info:** Depending on your SciPy version you might need to replace `as_matrix` with `as_dcm`

As you can see, apart from some minor floating-point error, the length (last 2 outputs) did not change. Furthermore, I chose the example point, so that it gets outside the unit cube. To address this problem, you need to find the maximum absolute value inside the transformed data. You can use `amax` and `amin` to get the maximum and minimum value ([see also here](https://stackoverflow.com/questions/55284090/how-to-find-max-value-in-2d-array-with-index)) if you put all your coordinates into one large 2d array (a matrix). Then compare the absolute values of the `amax` and `amin` results and pick the larger one. Divide all your coordinates (not the normals!) by this value, to scale your model back into the unit cube. Alternatively, you can create a uniform scaling matrix

$$
\begin{bmatrix}
s&0&0\\
0&s&0\\
0&0&s
\end{bmatrix}
$$

with $s$ being the reciprocal of the maximum absolute value. Multiply this matrix with all points.

To sum it up:

* calculate the rotation matrix with SciPy
* Multiply the rotation matrix with all points and normals
* find the maximum absolute value in the rotated data
* scale your coordinates with the found maximum value

**Remark:** If you put your points and normals into 2 matrices, you can apply the rotations and scaling matrices without a loop, which makes it much faster.

> **Comments:**
> **username_0**: But if the model is centered around the center (0,0,0) in a unit cube, is there really a need for rescaling points back to the unit cube?  Moreover, can I use the same rotation matrix for normals as I used for points?  
> **username_0**: also, I don't like your approach by scaling by maximum value across all axises (x,y,z), since it degrades pointcloud objects significantly. Say you have a pencil like object, if you scale it by it's maximum value, which is surely going to be along the pencil length, and divide both it's width and height by the same value, you will get something that looks more like a small radius stick than the pencil.  
> **username_1**: Question 1: Depends on your model. But take the unit cube itself as an example. If you rotate it by any angle that isn't a multiple of 90 degrees, The corners will end up outside the unit cube. To visualize it, take two dice and put them on top of each other so that they are aligned. Now rotate the upper one by 45 degrees. See the problem? Only if all your points are initially inside the unit sphere, you can be sure that no point will end up outside the unit cube after an arbitrary rotation.  
> **username_0**: Also, why scaling by some value, it's rotation and should be shape and length preserving, wouldn't shifting/translation be correct way of bringing object back to the unit cube?  
> **username_1**: Question 2: Yes, actually you HAVE to, otherwise you get wrong normals. A quote from my answer: "Normals are rotated the same way as the rest of your mesh/point cloud."  
> **username_1**: Regarding your second comment: If you use the scaling I described, it just shrinks the model. So you will just get a smaller pencil, but the ratio between thickness and length is preserved. Maybe you should read a little bit more about the basic operations that are used in computer graphics: Scaling, rotation, translation. See [this tutorial](https://learnopengl.com/Getting-started/Transformations).  
> **username_1**: Question of your 3. comment: Translation MIGHT work, but in case of the rotated unit cube (angles != 90° * N)  as a model, there is no way to translate it into the unrotated unit cube. The only way to fit it without scaling is to rotate it back.  
> **username_0**: Is centroid (central point of the pointcloud) preserved after rotation translation? Could I by just shifting centroid to 0,0,0 bring back my object to unit cube?  

---

