trimesh icon indicating copy to clipboard operation
trimesh copied to clipboard

Inconsistency in mesh loading after 4.6.0

Open domef opened this issue 7 months ago • 2 comments

I noticed that after version 4.6.0 meshes are loaded differently from the previous versions introducing a breaking change. I noticed in the change logs that some big changes has been made to the i/o modules, but I'm wondering if the following behaviour is expected.

Here is the script I used:

import tempfile

import numpy as np
import open3d as o3d
import trimesh

mesh_o3d = o3d.geometry.TriangleMesh.create_sphere()
mesh_o3d.compute_vertex_normals()
mesh_o3d.compute_triangle_normals()


vertices_1 = np.asarray(mesh_o3d.vertices)
triangles_1 = np.asarray(mesh_o3d.triangles)
vertices_normals_1 = np.asarray(mesh_o3d.vertex_normals)
triangles_normals_1 = np.asarray(mesh_o3d.triangle_normals)

mesh_1 = trimesh.Trimesh()
mesh_1.vertices = vertices_1
mesh_1.faces = triangles_1
mesh_1.vertex_normals = vertices_normals_1
mesh_1.face_normals = triangles_normals_1

with tempfile.NamedTemporaryFile(suffix=".ply") as tmp_file:
    mesh_1.export(tmp_file.name)
    mesh_2 = trimesh.load(tmp_file.name)
    # mesh_2 = trimesh.load(tmp_file.name, force="mesh")

    vertices_2 = np.asarray(mesh_2.vertices)
    triangles_2 = np.asarray(mesh_2.faces)
    vertices_normals_2 = np.asarray(mesh_2.vertex_normals)
    triangles_normals_2 = np.asarray(mesh_2.face_normals)

assert np.allclose(vertices_1, vertices_2)
assert np.allclose(triangles_1, triangles_2)
assert np.allclose(vertices_normals_1, vertices_normals_2)
assert np.allclose(triangles_normals_1, triangles_normals_2)

It creates a sphere with open3d, then it converts to trimesh and after writing and loading the same mesh I obtain different meshes.

If I use trimesh.load(tmp_file.name,) it always works. If I use trimesh.load(tmp_file.name, force="mesh") it only works with trimesh<4.6. Specifically only the vertices normals are loaded incorrectly, the other things are ok.

domef avatar Apr 16 '25 11:04 domef

Hey, yeah there was a major refactor of the loading system, and the full details are in https://github.com/mikedh/trimesh/pull/2241

The recommended new usage is trimesh.load_mesh(...) which generally the same as force=mesh. Although in order to always return a mesh it may have to call trimesh.util.concatenate, which may be dropping the vertex normals depending on the inputs. PR's with tests would be super welcome to make concatenate more consistent!

mikedh avatar Apr 17 '25 00:04 mikedh

I think the problem is related to the fact that the method copy is called (inside trimesh.util.concatenate) and it copies only vertices and faces but not the normals.

domef avatar Apr 17 '25 11:04 domef