mikedh / trimesh

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

mesh loading not order preserving? #147

Closed riaqn closed 6 years ago

riaqn commented 6 years ago

I realized recently that when a mesh is loaded, the vertex order is not preserved? That is, mesh.vertices[0] is not the first vertex in the original mesh file.

the format I'm using is OFF.

I feel this is fundementally problematic, and can cause serious confusion to users.

mikedh commented 6 years ago

Hey, this actually came up very recently in this thread

OBJ supports some weird cases so its hard to guarantee ordering in all cases, but the fix in https://github.com/mikedh/trimesh/commit/c019a25874fec33ca6ec3094621743711a29623f should preserve vertex and face order in the simple cases if you load your mesh with processing disabled: mesh = trimesh.load('stuff.OBJ', process=False)

You can get the update with: pip install --upgrade trimesh

mikedh commented 6 years ago

Oh sorry, I misread OBJ vs OFF. Disabling process should work in that case too, though its not in tests.

riaqn commented 6 years ago

Thanks for the lightning reply @mikedh. This workaround works for me.

I suggest making that the default value if it won't compromise functionalities substantially.

Thank you.

sqwhong commented 5 years ago

I also found that when calling

path = mesh.outline()

The order of vertices attribute in mesh and path is different. I wonder if there's a way to address this issue.

Edit: I tried:

path = mesh.outline(process=False)

And this seems to be able to solve my issue!

tuqubao commented 5 years ago
  1. import numpy as np

  2. import trimesh

  3. p = r'C:\Users\admin\Desktop\test\test_02.obj'

  4. mesh = trimesh.load( p, process = False )

  5. print(mesh.vertices)

the vertex order is not preserved. how to do that? I has upgraded trimesh, with pip install --upgrade trimesh, the problem is still existe.

this is ouput:

  1. [[-2.5 -2.5 2.5]
  2. [-2.5 -2.5 2.5]
  3. [-2.5 -2.5 2.5]
  4. [ 2.5 -2.5 2.5]
  5. [ 2.5 -2.5 2.5]
  6. [ 2.5 -2.5 2.5]
  7. [-2.5 2.5 2.5]
  8. [-2.5 2.5 2.5]
  9. [-2.5 2.5 2.5]
  10. [ 2.5 2.5 2.5]
  11. [ 2.5 2.5 2.5]
  12. [ 2.5 2.5 2.5]
  13. [-2.5 2.5 -2.5]
  14. [-2.5 2.5 -2.5]
  15. [-2.5 2.5 -2.5]
  16. [ 2.5 2.5 -2.5]
  17. [ 2.5 2.5 -2.5]
  18. [ 2.5 2.5 -2.5]
  19. [-2.5 -2.5 -2.5]
  20. [-2.5 -2.5 -2.5]
  21. [-2.5 -2.5 -2.5]
  22. [ 2.5 -2.5 -2.5]
  23. [ 2.5 -2.5 -2.5]
  24. [ 2.5 -2.5 -2.5]]

the answer should be: [[-2.5, -2.5, 2.5] [2.5, -2.5, 2.5] [-2.5, 2.5, 2.5] [ 2.5, 2.5, 2.5] [-2.5, 2.5, -2.5] [ 2.5, 2.5, -2.5] [-2.5, -2.5, -2.5] [ 2.5, -2.5, -2.5]]

the number of vertex and order is wrong.

how to fix the problem?

tuqubao commented 5 years ago

I found the code from wavefront.py 235 current['v'].append(attribs['v'][int(f_split[0]) - 1])

attribs['v'] store all the vertex message, include position and order. but current['v'] copy vertex base on face message. and final the return mesh include the current['v'] message is face to vertex info. the vertex's order message is miss. I hope you fix the bug maybe that is current['v'] = attribs['v'] because attribs['v'] have a right vertex's info.

tuqubao commented 5 years ago

I doubt setup process = False will work the problem, because the load_wavefront() return the data is miss order info, you can't rebuild it.

zhan-xu commented 4 years ago

Yeah same here. Sometimes load_mesh gets the wrong number of vertices from an OBJ file, although I used process=False

mikedh commented 4 years ago

Hey, this is likely from the way OBJ encodes vertices, vertex normals, and vertex UV's. Faces like this:

f 3//5 8//5 4//5

Will have vertices expanded as we consider 2//1 as a different vertex from 2//3 because if the position is the same but the texture coordinate is different we have to refer it differently in the simple data structure trimesh uses. I'd suggest using a different format with a more aligned data structure (i.e. GLB) if this is a major issue for you.

aluo-x commented 3 years ago

I was also very confused recently by the differing number of vertices between the orig OBJ & the loaded mesh data. Any thoughts on reducing the difference?

mikedh commented 3 years ago

Hey, have you tried loading with process=False?

In [1]: import trimesh
f
In [2]: fn = 'duck.obj'

In [3]: with open(fn, 'r') as f:
   ...:     text = f.read()
   ...:     

In [4]: text.count('v ')
Out[4]: 2399

In [5]: m = trimesh.load(fn)

In [6]: m.vertices.shape
Out[6]: (2277, 3)

In [7]: m = trimesh.load(fn, process=False)

In [8]: m.vertices.shape
Out[8]: (2399, 3)
aluo-x commented 3 years ago

First thing I tried. The mesh was a level 4 icosphere directly exported from Blender. So it was well behaved.

mikedh commented 3 years ago

I just checked the blender export and it's exporting faces like: f 3//5 8//5 4//5

Which are being unmerged to provide the flat data structure. If we add Yet Another Boolean Kwarg to skip this (skip_uv? skip_unmerge? idk) we can get the count to match:

In [2]: a = trimesh.load('ico4.obj', process=False)

In [3]: a
Out[3]: <trimesh.Trimesh(vertices.shape=(3840, 3), faces.shape=(1280, 3))>

In [4]: a = trimesh.load('ico4.obj', process=False, skip_uv=True)

In [5]: 

In [5]: a
Out[5]: <trimesh.Trimesh(vertices.shape=(642, 3), faces.shape=(1280, 3))>

In [6]: with open('ico4.obj', 'r') as f:
   ...:     print(f.read().count('v '))
   ...:     
642

But as far as I can tell it does generally mean discarding UV's and normals. Happy to add if it'd be useful!

aluo-x commented 3 years ago

Would be much appreciated! Its unfortunate that OBJ has so many edge cases.

mikedh commented 3 years ago

@aluo-x I added the maintain_order kwarg to the OBJ loader and to the unmerge_faces function, let me know if this doesn't work for you. It's explicit enough that any reordering of vertices from the original would then be a bug we can fix as opposed to just unexpected behavior :smile::

trimesh.load('model.obj', process=False, maintain_order=True)

Andrewymd commented 3 years ago

@aluo-x I added the maintain_order kwarg to the OBJ loader and to the unmerge_faces function, let me know if this doesn't work for you. It's explicit enough that any reordering of vertices from the original would then be a bug we can fix as opposed to just unexpected behavior :

trimesh.load('model.obj', process=False, maintain_order=True)

Thanks, it's work for me

aefull commented 2 years ago

In addition to the vertices, Edge also comes in a different order. Neighbor vertices is the same mesh, Sometimes it returns differently.