@@ -1545,27 +1545,35 @@ def sample_textures(self, fragments):
15451545 else :
15461546 raise ValueError ("Meshes does not have textures" )
15471547
1548- def centroid (self ):
1548+ def volume_centroid (self ):
15491549 """
15501550 Compute the volumetric centroid of this mesh, which is distinct from the center of mass.
15511551 The center of mass (average of all vertices) will be closer to where there are a
15521552 higher density of points in a mesh are, but the centroid, which is based on volume,
15531553 will be closer to a perceived center of the mesh, as opposed to based on the density
1554- of vertices.
1554+ of vertices. This function assumes that the mesh is watertight, and that the faces are
1555+ all oriented in the same direction.
15551556
15561557 Returns:
15571558 The position of the centroid as a tensor of shape (3).
15581559 """
1559- v_idxs = self .faces_packed ().split ([1 , 1 , 1 ], dim = - 1 )
1560- verts = self .verts_packed ()
1561- v0 , v1 , v2 = [verts [idx ].squeeze (- 2 ) for idx in v_idxs ]
1560+ v_idxs = self .faces_padded ().split ([1 , 1 , 1 ], dim = - 1 )
1561+ verts = self .verts_padded ()
1562+
1563+ v0 , v1 , v2 = [torch .gather (verts , 1 , idx .expand (- 1 , - 1 , 3 )) for idx in v_idxs ]
1564+
15621565 tetra_center = (v0 + v1 + v2 ) / 4
15631566 signed_tetra_vol = (v0 * torch .cross (v1 , v2 , dim = - 1 )).sum (
15641567 dim = - 1 , keepdim = True
15651568 ) / 6
1566- return (tetra_center * signed_tetra_vol ).sum (dim = - 2 ) / signed_tetra_vol .sum (
1567- dim = - 2
1568- ).clamp (min = 1e-5 )
1569+ denom = signed_tetra_vol .sum (dim = - 2 )
1570+ # clamp the denominator to prevent instability for degenerate meshes.
1571+ denom = torch .where (
1572+ denom < 0 ,
1573+ denom .clamp (max = - 1e-5 ),
1574+ denom .clamp (min = 1e-5 )
1575+ )
1576+ return (tetra_center * signed_tetra_vol ).sum (dim = - 2 ) / denom
15691577
15701578 def submeshes (
15711579 self ,
0 commit comments