Skip to content

Commit

Permalink
Submeshing TexturesAtlas for PyTorch3D 3D Rendering
Browse files Browse the repository at this point in the history
Summary: Implement submeshing for TexturesAtlas and add associated test

Reviewed By: bottler

Differential Revision: D52334053

fbshipit-source-id: d54080e9af1f0c01551702736e858e3bd439ac58
  • Loading branch information
ttanpcs authored and facebook-github-bot committed Dec 21, 2023
1 parent 8a27590 commit e46ab49
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 2 deletions.
27 changes: 27 additions & 0 deletions pytorch3d/renderer/mesh/textures.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,33 @@ def sample_textures(self, fragments, **kwargs) -> torch.Tensor:

return texels

def submeshes(
self,
vertex_ids_list: List[List[torch.LongTensor]],
faces_ids_list: List[List[torch.LongTensor]],
) -> "TexturesAtlas":
"""
Extract a sub-texture for use in a submesh.
If the meshes batch corresponding to this TextureAtlas contains
`n = len(faces_ids_list)` meshes, then self.atlas_list()
will be of length n. After submeshing, we obtain a batch of
`k = sum(len(v) for v in atlas_list` submeshes (see Meshes.submeshes). This
function creates a corresponding TexturesAtlas object with `atlas_list`
of length `k`.
"""
if len(faces_ids_list) != len(self.atlas_list()):
raise IndexError(
"faces_ids_list must be of " "the same length as atlas_list."
)

sub_features = []
for atlas, faces_ids in zip(self.atlas_list(), faces_ids_list):
for faces_ids_submesh in faces_ids:
sub_features.append(atlas[faces_ids_submesh])

return self.__class__(sub_features)

def faces_verts_textures_packed(self) -> torch.Tensor:
"""
Samples texture from each vertex for each face in the mesh.
Expand Down
2 changes: 0 additions & 2 deletions pytorch3d/structures/meshes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1576,8 +1576,6 @@ def submeshes(
Returns:
Meshes object of length `sum(len(ids) for ids in face_indices)`.
Submeshing only works with no textures, TexturesVertex, or TexturesUV.
Example 1:
If `meshes` has batch size 1, and `face_indices` is a 1D LongTensor,
Expand Down
33 changes: 33 additions & 0 deletions tests/test_texturing.py
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,39 @@ def test_sample_textures_error(self):
with self.assertRaisesRegex(ValueError, "do not match the dimensions"):
meshes.sample_textures(None)

def test_submeshes(self):
N = 2
V = 5
F = 5
tex = TexturesAtlas(
atlas=torch.arange(N * F * 4 * 4 * 3, dtype=torch.float32).reshape(
N, F, 4, 4, 3
)
)

verts = torch.rand(size=(N, V, 3))
faces = torch.randint(size=(N, F, 3), high=V)
mesh = Meshes(verts=verts, faces=faces, textures=tex)

sub_faces = [
[torch.tensor([0, 2]), torch.tensor([1, 2])],
[],
]
subtex = mesh.submeshes(sub_faces).textures
subtex_faces = subtex.atlas_list()

self.assertEqual(len(subtex_faces), 2)
self.assertClose(
subtex_faces[0].flatten().msort(),
torch.cat(
(
torch.arange(4 * 4 * 3, dtype=torch.float32),
torch.arange(96, 96 + 4 * 4 * 3, dtype=torch.float32),
),
0,
),
)


class TestTexturesUV(TestCaseMixin, unittest.TestCase):
def setUp(self) -> None:
Expand Down

0 comments on commit e46ab49

Please sign in to comment.