@@ -462,9 +462,9 @@ def verts_list(self):
462
462
assert (
463
463
self ._verts_padded is not None
464
464
), "verts_padded is required to compute verts_list."
465
- self ._verts_list = [
466
- v [ 0 ] for v in self ._verts_padded . split ([ 1 ] * self ._N , 0 )
467
- ]
465
+ self ._verts_list = struct_utils . padded_to_list (
466
+ self ._verts_padded , self .num_verts_per_mesh (). tolist ( )
467
+ )
468
468
return self ._verts_list
469
469
470
470
def faces_list (self ):
@@ -478,10 +478,9 @@ def faces_list(self):
478
478
assert (
479
479
self ._faces_padded is not None
480
480
), "faces_padded is required to compute faces_list."
481
- self ._faces_list = []
482
- for i in range (self ._N ):
483
- valid = self ._faces_padded [i ].gt (- 1 ).all (1 )
484
- self ._faces_list .append (self ._faces_padded [i , valid , :])
481
+ self ._faces_list = struct_utils .padded_to_list (
482
+ self ._faces_padded , self .num_faces_per_mesh ().tolist ()
483
+ )
485
484
return self ._faces_list
486
485
487
486
def verts_packed (self ):
@@ -525,7 +524,6 @@ def num_verts_per_mesh(self):
525
524
Returns:
526
525
1D tensor of sizes.
527
526
"""
528
- self ._compute_packed ()
529
527
return self ._num_verts_per_mesh
530
528
531
529
def faces_packed (self ):
@@ -590,7 +588,6 @@ def num_faces_per_mesh(self):
590
588
Returns:
591
589
1D tensor of sizes.
592
590
"""
593
- self ._compute_packed ()
594
591
return self ._num_faces_per_mesh
595
592
596
593
def edges_packed (self ):
@@ -664,14 +661,13 @@ def verts_padded_to_packed_idx(self):
664
661
Returns:
665
662
1D tensor of indices.
666
663
"""
667
- self ._compute_packed ()
668
664
if self ._verts_padded_to_packed_idx is not None :
669
665
return self ._verts_padded_to_packed_idx
670
666
671
667
self ._verts_padded_to_packed_idx = torch .cat (
672
668
[
673
669
torch .arange (v , dtype = torch .int64 , device = self .device ) + i * self ._V
674
- for (i , v ) in enumerate (self ._num_verts_per_mesh )
670
+ for (i , v ) in enumerate (self .num_verts_per_mesh () )
675
671
],
676
672
dim = 0 ,
677
673
)
@@ -862,8 +858,8 @@ def _compute_padded(self, refresh: bool = False):
862
858
):
863
859
return
864
860
865
- verts_list = self ._verts_list
866
- faces_list = self ._faces_list
861
+ verts_list = self .verts_list ()
862
+ faces_list = self .faces_list ()
867
863
assert (
868
864
faces_list is not None and verts_list is not None
869
865
), "faces_list and verts_list arguments are required"
@@ -943,13 +939,15 @@ def _compute_packed(self, refresh: bool = False):
943
939
944
940
verts_list_to_packed = struct_utils .list_to_packed (verts_list )
945
941
self ._verts_packed = verts_list_to_packed [0 ]
946
- self ._num_verts_per_mesh = verts_list_to_packed [1 ]
942
+ if not torch .allclose (self .num_verts_per_mesh (), verts_list_to_packed [1 ]):
943
+ raise ValueError ("The number of verts per mesh should be consistent." )
947
944
self ._mesh_to_verts_packed_first_idx = verts_list_to_packed [2 ]
948
945
self ._verts_packed_to_mesh_idx = verts_list_to_packed [3 ]
949
946
950
947
faces_list_to_packed = struct_utils .list_to_packed (faces_list )
951
948
faces_packed = faces_list_to_packed [0 ]
952
- self ._num_faces_per_mesh = faces_list_to_packed [1 ]
949
+ if not torch .allclose (self .num_faces_per_mesh (), faces_list_to_packed [1 ]):
950
+ raise ValueError ("The number of faces per mesh should be consistent." )
953
951
self ._mesh_to_faces_packed_first_idx = faces_list_to_packed [2 ]
954
952
self ._faces_packed_to_mesh_idx = faces_list_to_packed [3 ]
955
953
@@ -1328,6 +1326,100 @@ def scale_verts(self, scale):
1328
1326
new_mesh = self .clone ()
1329
1327
return new_mesh .scale_verts_ (scale )
1330
1328
1329
+ def update_padded (self , new_verts_padded ):
1330
+ """
1331
+ This function allows for an pdate of verts_padded without having to
1332
+ explicitly convert it to the list representation for heterogeneous batches.
1333
+ Returns a Meshes structure with updated padded tensors and copies of the
1334
+ auxiliary tensors at construction time.
1335
+ It updates self._verts_padded with new_verts_padded, and does a
1336
+ shallow copy of (faces_padded, faces_list, num_verts_per_mesh, num_faces_per_mesh).
1337
+ If packed representations are computed in self, they are updated as well.
1338
+
1339
+ Args:
1340
+ new_points_padded: FloatTensor of shape (N, V, 3)
1341
+
1342
+ Returns:
1343
+ Meshes with updated padded representations
1344
+ """
1345
+
1346
+ def check_shapes (x , size ):
1347
+ if x .shape [0 ] != size [0 ]:
1348
+ raise ValueError ("new values must have the same batch dimension." )
1349
+ if x .shape [1 ] != size [1 ]:
1350
+ raise ValueError ("new values must have the same number of points." )
1351
+ if x .shape [2 ] != size [2 ]:
1352
+ raise ValueError ("new values must have the same dimension." )
1353
+
1354
+ check_shapes (new_verts_padded , [self ._N , self ._V , 3 ])
1355
+
1356
+ new = self .__class__ (verts = new_verts_padded , faces = self .faces_padded ())
1357
+
1358
+ if new ._N != self ._N or new ._V != self ._V or new ._F != self ._F :
1359
+ raise ValueError ("Inconsistent sizes after construction." )
1360
+
1361
+ # overwrite the equisized flag
1362
+ new .equisized = self .equisized
1363
+
1364
+ # overwrite textures if any
1365
+ new .textures = self .textures
1366
+
1367
+ # copy auxiliary tensors
1368
+ copy_tensors = ["_num_verts_per_mesh" , "_num_faces_per_mesh" , "valid" ]
1369
+
1370
+ for k in copy_tensors :
1371
+ v = getattr (self , k )
1372
+ if torch .is_tensor (v ):
1373
+ setattr (new , k , v ) # shallow copy
1374
+
1375
+ # shallow copy of faces_list if any, st new.faces_list()
1376
+ # does not re-compute from _faces_padded
1377
+ new ._faces_list = self ._faces_list
1378
+
1379
+ # update verts/faces packed if they are computed in self
1380
+ if self ._verts_packed is not None :
1381
+ copy_tensors = [
1382
+ "_faces_packed" ,
1383
+ "_verts_packed_to_mesh_idx" ,
1384
+ "_faces_packed_to_mesh_idx" ,
1385
+ "_mesh_to_verts_packed_first_idx" ,
1386
+ "_mesh_to_faces_packed_first_idx" ,
1387
+ ]
1388
+ for k in copy_tensors :
1389
+ v = getattr (self , k )
1390
+ assert torch .is_tensor (v )
1391
+ setattr (new , k , v ) # shallow copy
1392
+ # update verts_packed
1393
+ pad_to_packed = self .verts_padded_to_packed_idx ()
1394
+ new_verts_packed = new_verts_padded .reshape (- 1 , 3 )[pad_to_packed , :]
1395
+ new ._verts_packed = new_verts_packed
1396
+ new ._verts_padded_to_packed_idx = pad_to_packed
1397
+
1398
+ # update edges packed if they are computed in self
1399
+ if self ._edges_packed is not None :
1400
+ copy_tensors = [
1401
+ "_edges_packed" ,
1402
+ "_edges_packed_to_mesh_idx" ,
1403
+ "_mesh_to_edges_packed_first_idx" ,
1404
+ "_faces_packed_to_edges_packed" ,
1405
+ "_num_edges_per_mesh" ,
1406
+ ]
1407
+ for k in copy_tensors :
1408
+ v = getattr (self , k )
1409
+ assert torch .is_tensor (v )
1410
+ setattr (new , k , v ) # shallow copy
1411
+
1412
+ # update laplacian if it is compute in self
1413
+ if self ._laplacian_packed is not None :
1414
+ new ._laplacian_packed = self ._laplacian_packed
1415
+
1416
+ assert new ._verts_list is None
1417
+ assert new ._verts_normals_packed is None
1418
+ assert new ._faces_normals_packed is None
1419
+ assert new ._faces_areas_packed is None
1420
+
1421
+ return new
1422
+
1331
1423
# TODO(nikhilar) Move function to utils file.
1332
1424
def get_bounding_boxes (self ):
1333
1425
"""
0 commit comments