mikedh / trimesh

Python library for loading and using triangular meshes.
https://trimesh.org
MIT License
2.94k stars 574 forks source link

Scale Issue #1743

Closed albertotono closed 1 year ago

albertotono commented 1 year ago

Then I am trying to scale a mesh Scene, it looks I have two issues:

1) The order of the Scene Geometry is inverted 2) The scale factor is off?

Using Pytorch3D

verts, faces, aux = load_obj(FILE_PATH)
device = torch.device("cuda:0")
faces_idx = faces.verts_idx.to(device)
verts = verts.to(device)
center = verts.mean(0)
verts = verts - center
scale = max(verts.abs().max(0)[0])
verts_Pytorch3D_scaled = verts / scale

mesh = trimesh.load_mesh(FILE_PATH)
verts_Trimesh_scaled = mesh.scaled(1.0/scale)

image

verts_Pytorch3D_scaled != verts_Trimesh_scaled??
image

Why is this happening? Would be possible to preserve the scaling factor and order?

What would be the best way to scale meshes in Trimesh Scene preserving order and with the right scale?

albertotono commented 1 year ago

I think the order issue is more related to Pytorch3D, but how to properly scale my mesh, and normalize it to [-1,1] or [-0.5 , 0.5] cube.

albertotono commented 1 year ago

This helps https://github.com/mikedh/trimesh/issues/1358 on the scaling, I think the issue is centering the mesh properly.

mikedh commented 1 year ago

Hey, not sure what Pytorch is doing, but the current trimesh behavior seems like it's not re-ordering or inverting for a simple example:

    s = trimesh.creation.box().scene()

    scaling = 1.0 / 3.0
    c = s.scaled(scaling)

    factor = (c.geometry['geometry_0'].vertices /
              s.geometry['geometry_0'].vertices)

    assert np.allclose(factor, scaling)
albertotono commented 1 year ago

Yes, agree. I think Kaolin is based on Trimesh, not sure about Pytorch3D. The order issue is on Pytorch3D confirmed.

Any quick idea how to centering properly?

mikedh commented 1 year ago

Hey, rough-and-ready scaled(1/scene.extents) might do it:

In [2]: m = trimesh.load('models/cycloidal.3DXML')
DEBUG              load.py:227   loaded <trimesh.Scene(len(geometry)=13)> using load_3DXML
DEBUG         constants.py:154   load_mesh executed in 0.1340 seconds.

In [3]: m
Out[3]: <trimesh.Scene(len(geometry)=13)>

In [4]: m.apply_transform(trimesh.transformations.random_rotation_matrix())

In [5]: m.bounds
DEBUG           caching.py:396   1 items cleared from cache: [('world', 'cycloidal')]
Out[5]: 
array([[-39.57966, -58.59546, -45.15146],
       [ 55.74367,  46.8527 ,  58.15404]])

In [6]: m.extents
Out[6]: array([ 95.32333, 105.44816, 103.3055 ])

In [7]: s = m.scaled(1/m.extents)

In [8]: s.extents
Out[8]: array([0.9904, 1.0017, 1.    ])

In [9]: s.bounds.mean(axis=0)
Out[9]: array([ 0.07999, -0.05653,  0.06293])

In [10]: s.apply_translation(-s.bounds.mean(axis=0))

In [11]: s.bounds
DEBUG           caching.py:396   3 items cleared from cache: ['bounds_corners', 'bounds', 'extents']
Out[11]: 
array([[-0.41521, -0.55738, -0.43707],
       [ 0.57519,  0.44432,  0.56293]])
albertotono commented 1 year ago

I am have a couple of issues:

Probably I have an old version of Trimesh. ( I installed via pip install Trimesh (3.9.31)))

image https://github.com/mikedh/trimesh/blob/d609429aa6afb62148819f2bcb950a23d4972f4d/trimesh/scene/scene.py#L996 and Also when I apply_translation it produce an NoneType

Thanks @mikedh,

PS: I guess it could be created a normalization function for having both, scale and centering. Happy to PR it if needed.

mikedh commented 1 year ago

Yeah the non-uniform scaling was just released yesterday: https://github.com/mikedh/trimesh/pull/1732

There was a weird caching bug and a backwards dot product preventing this from working, added a fix and test in the followup release #1742 which I'll merge as soon as tests pass. I think this is close to working (PR's welcome!):

In [1]: import trimesh
m 
In [2]: m = trimesh.load('models/cycloidal.3DXML')

In [3]: m.apply_transform(trimesh.transformations.random_rotation_matrix())
Out[3]: <trimesh.Scene(len(geometry)=13)>

In [4]: m.bounds[0]
Out[4]: array([-56.02267239, -40.44721501, -36.03040504])

In [5]: s = m.scaled(1/m.extents)

In [6]: s.extents
Out[6]: array([1.01144344, 1.0091659 , 1.        ])

In [7]: s.apply_translation(-s.bounds.mean(axis=0))
Out[7]: <trimesh.Scene(len(geometry)=72)>

In [8]: s.bounds
Out[8]: 
array([[-0.50572172, -0.50458295, -0.5       ],
       [ 0.50572172,  0.50458295,  0.5       ]])
albertotono commented 1 year ago

To keep in mind that it is crucial to first scale and then translate as you are doing.

I think also Pytorch3D has does the opposite in their example, and the geometry is not well centered. [ First on the left ] .

Here in Trimesh, it would be great to Normalize it properly. It would be nice to have that scale factor that Pytorch3D has. scale = max(verts.abs().max(0)[0]) image