9
9
10
10
import numpy as np
11
11
import torch
12
+ from iopath .common .file_io import PathManager
12
13
from pytorch3d .io .mtl_io import load_mtl , make_mesh_texture_atlas
13
14
from pytorch3d .io .utils import _check_faces_indices , _make_tensor , _open_file
14
15
from pytorch3d .renderer import TexturesAtlas , TexturesUV
@@ -68,6 +69,7 @@ def load_obj(
68
69
texture_atlas_size : int = 4 ,
69
70
texture_wrap : Optional [str ] = "repeat" ,
70
71
device = "cpu" ,
72
+ path_manager : Optional [PathManager ] = None ,
71
73
):
72
74
"""
73
75
Load a mesh from a .obj file and optionally textures from a .mtl file.
@@ -139,6 +141,7 @@ def load_obj(
139
141
If `texture_mode="clamp"` the values are clamped to the range [0, 1].
140
142
If None, then there is no transformation of the texture values.
141
143
device: string or torch.device on which to return the new tensors.
144
+ path_manager: optionally a PathManager object to interpret paths.
142
145
143
146
Returns:
144
147
6-element tuple containing
@@ -207,14 +210,17 @@ def load_obj(
207
210
# pyre-fixme[6]: Expected `_PathLike[Variable[typing.AnyStr <: [str,
208
211
# bytes]]]` for 1st param but got `Union[_PathLike[typing.Any], bytes, str]`.
209
212
data_dir = os .path .dirname (f )
210
- with _open_file (f , "r" ) as f :
213
+ if path_manager is None :
214
+ path_manager = PathManager ()
215
+ with _open_file (f , path_manager , "r" ) as f :
211
216
return _load_obj (
212
217
f ,
213
- data_dir ,
218
+ data_dir = data_dir ,
214
219
load_textures = load_textures ,
215
220
create_texture_atlas = create_texture_atlas ,
216
221
texture_atlas_size = texture_atlas_size ,
217
222
texture_wrap = texture_wrap ,
223
+ path_manager = path_manager ,
218
224
device = device ,
219
225
)
220
226
@@ -226,6 +232,7 @@ def load_objs_as_meshes(
226
232
create_texture_atlas : bool = False ,
227
233
texture_atlas_size : int = 4 ,
228
234
texture_wrap : Optional [str ] = "repeat" ,
235
+ path_manager : Optional [PathManager ] = None ,
229
236
):
230
237
"""
231
238
Load meshes from a list of .obj files using the load_obj function, and
@@ -234,11 +241,13 @@ def load_objs_as_meshes(
234
241
details. material_colors and normals are not stored.
235
242
236
243
Args:
237
- f : A list of file-like objects (with methods read, readline, tell,
238
- and seek), pathlib paths or strings containing file names.
244
+ files : A list of file-like objects (with methods read, readline, tell,
245
+ and seek), pathlib paths or strings containing file names.
239
246
device: Desired device of returned Meshes. Default:
240
247
uses the current device for the default tensor type.
241
248
load_textures: Boolean indicating whether material files are loaded
249
+ create_texture_atlas, texture_atlas_size, texture_wrap: as for load_obj.
250
+ path_manager: optionally a PathManager object to interpret paths.
242
251
243
252
Returns:
244
253
New Meshes object.
@@ -251,6 +260,7 @@ def load_objs_as_meshes(
251
260
create_texture_atlas = create_texture_atlas ,
252
261
texture_atlas_size = texture_atlas_size ,
253
262
texture_wrap = texture_wrap ,
263
+ path_manager = path_manager ,
254
264
)
255
265
tex = None
256
266
if create_texture_atlas :
@@ -431,7 +441,13 @@ def _parse_obj(f, data_dir: str):
431
441
432
442
433
443
def _load_materials (
434
- material_names : List [str ], f , data_dir : str , * , load_textures : bool , device
444
+ material_names : List [str ],
445
+ f ,
446
+ * ,
447
+ data_dir : str ,
448
+ load_textures : bool ,
449
+ device ,
450
+ path_manager : PathManager ,
435
451
):
436
452
"""
437
453
Load materials and optionally textures from the specified path.
@@ -442,6 +458,7 @@ def _load_materials(
442
458
data_dir: the directory where the material texture files are located.
443
459
load_textures: whether textures should be loaded.
444
460
device: string or torch.device on which to return the new tensors.
461
+ path_manager: PathManager object to interpret paths.
445
462
446
463
Returns:
447
464
material_colors: dict of properties for each material.
@@ -460,16 +477,24 @@ def _load_materials(
460
477
return None , None
461
478
462
479
# Texture mode uv wrap
463
- return load_mtl (f , material_names , data_dir , device = device )
480
+ return load_mtl (
481
+ f ,
482
+ material_names = material_names ,
483
+ data_dir = data_dir ,
484
+ path_manager = path_manager ,
485
+ device = device ,
486
+ )
464
487
465
488
466
489
def _load_obj (
467
490
f_obj ,
491
+ * ,
468
492
data_dir ,
469
493
load_textures : bool = True ,
470
494
create_texture_atlas : bool = False ,
471
495
texture_atlas_size : int = 4 ,
472
496
texture_wrap : Optional [str ] = "repeat" ,
497
+ path_manager : PathManager ,
473
498
device = "cpu" ,
474
499
):
475
500
"""
@@ -522,7 +547,12 @@ def _load_obj(
522
547
523
548
texture_atlas = None
524
549
material_colors , texture_images = _load_materials (
525
- material_names , mtl_path , data_dir , load_textures = load_textures , device = device
550
+ material_names ,
551
+ mtl_path ,
552
+ data_dir = data_dir ,
553
+ load_textures = load_textures ,
554
+ path_manager = path_manager ,
555
+ device = device ,
526
556
)
527
557
528
558
if create_texture_atlas :
@@ -562,7 +592,13 @@ def _load_obj(
562
592
return verts , faces , aux
563
593
564
594
565
- def save_obj (f , verts , faces , decimal_places : Optional [int ] = None ):
595
+ def save_obj (
596
+ f ,
597
+ verts ,
598
+ faces ,
599
+ decimal_places : Optional [int ] = None ,
600
+ path_manager : Optional [PathManager ] = None ,
601
+ ):
566
602
"""
567
603
Save a mesh to an .obj file.
568
604
@@ -571,6 +607,8 @@ def save_obj(f, verts, faces, decimal_places: Optional[int] = None):
571
607
verts: FloatTensor of shape (V, 3) giving vertex coordinates.
572
608
faces: LongTensor of shape (F, 3) giving faces.
573
609
decimal_places: Number of decimal places for saving.
610
+ path_manager: Optional PathManager for interpreting f if
611
+ it is a str.
574
612
"""
575
613
if len (verts ) and not (verts .dim () == 2 and verts .size (1 ) == 3 ):
576
614
message = "Argument 'verts' should either be empty or of shape (num_verts, 3)."
@@ -580,7 +618,10 @@ def save_obj(f, verts, faces, decimal_places: Optional[int] = None):
580
618
message = "Argument 'faces' should either be empty or of shape (num_faces, 3)."
581
619
raise ValueError (message )
582
620
583
- with _open_file (f , "w" ) as f :
621
+ if path_manager is None :
622
+ path_manager = PathManager ()
623
+
624
+ with _open_file (f , path_manager , "w" ) as f :
584
625
return _save (f , verts , faces , decimal_places )
585
626
586
627
0 commit comments