docstr: Meshes with TexturesUV joined into a scene
docstr_tok: ["Meshes","with","TexturesUV","joined","into","a","scene"]
code: def _join_uvs(self, rasterizer_type):
      """Meshes with TexturesUV joined into a scene"""
      # Test the result of rendering three tori with separate textures.
      # The expected result is consistent with rendering them each alone.
      # This tests TexturesUV.join_scene with rectangle flipping,
      # and we check the form of the merged map as well.
      torch.manual_seed(1)
      device = torch.device("cuda:0")
  
      R, T = look_at_view_transform(18, 0, 0)
      cameras = FoVPerspectiveCameras(device=device, R=R, T=T)
  
      raster_settings = RasterizationSettings(
          image_size=256, blur_radius=0.0, faces_per_pixel=1
      )
  
      lights = AmbientLights(device=device)
      blend_params = BlendParams(
          sigma=0.5,
          gamma=1e-4,
          background_color=torch.tensor([1.0, 1.0, 1.0], device=device),
      )
      rasterizer = rasterizer_type(
          cameras=cameras, raster_settings=raster_settings
      )
      if rasterizer_type == MeshRasterizer:
          shader = HardPhongShader(
              device=device,
              blend_params=blend_params,
              cameras=cameras,
              lights=lights,
          )
      else:
          shader = SplatterPhongShader(
              device=device,
              blend_params=blend_params,
              cameras=cameras,
              lights=lights,
          )
      renderer = MeshRenderer(rasterizer, shader)
  
      plain_torus = torus(r=1, R=4, sides=5, rings=6, device=device)
      [verts] = plain_torus.verts_list()
      verts_shifted1 = verts.clone()
      verts_shifted1 *= 0.5
      verts_shifted1[:, 1] += 7
      verts_shifted2 = verts.clone()
      verts_shifted2 *= 0.5
      verts_shifted2[:, 1] -= 7
      verts_shifted3 = verts.clone()
      verts_shifted3 *= 0.5
      verts_shifted3[:, 1] -= 700
  
      [faces] = plain_torus.faces_list()
      nocolor = torch.zeros((100, 100), device=device)
      color_gradient = torch.linspace(0, 1, steps=100, device=device)
      color_gradient1 = color_gradient[None].expand_as(nocolor)
      color_gradient2 = color_gradient[:, None].expand_as(nocolor)
      colors1 = torch.stack(
          [nocolor, color_gradient1, color_gradient2], dim=2
      )
      colors2 = torch.stack(
          [color_gradient1, color_gradient2, nocolor], dim=2
      )
      verts_uvs1 = torch.rand(size=(verts.shape[0], 2), device=device)
      verts_uvs2 = torch.rand(size=(verts.shape[0], 2), device=device)
  
      for i, align_corners, padding_mode in [
          (0, True, "border"),
          (1, False, "border"),
          (2, False, "zeros"),
      ]:
          textures1 = TexturesUV(
              maps=[colors1],
              faces_uvs=[faces],
              verts_uvs=[verts_uvs1],
              align_corners=align_corners,
              padding_mode=padding_mode,
          )
  
          # These downsamplings of colors2 are chosen to ensure a flip and a non flip
          # when the maps are merged.
          # We have maps of size (100, 100), (50, 99) and (99, 50).
          textures2 = TexturesUV(
              maps=[colors2[::2, :-1]],
              faces_uvs=[faces],
              verts_uvs=[verts_uvs2],
              align_corners=align_corners,
              padding_mode=padding_mode,
          )
          offset = torch.tensor([0, 0, 0.5], device=device)
          textures3 = TexturesUV(
              maps=[colors2[:-1, ::2] + offset],
              faces_uvs=[faces],
              verts_uvs=[verts_uvs2],
              align_corners=align_corners,
              padding_mode=padding_mode,
          )
          mesh1 = Meshes(
              verts=[verts], faces=[faces], textures=textures1
          )
          mesh2 = Meshes(
              verts=[verts_shifted1], faces=[faces], textures=textures2
          )
          mesh3 = Meshes(
              verts=[verts_shifted2], faces=[faces], textures=textures3
          )
          # mesh4 is like mesh1 but outside the field of view. It is here to test
          # that having another texture with the same map doesn't produce
          # two copies in the joined map.
          mesh4 = Meshes(
              verts=[verts_shifted3], faces=[faces], textures=textures1
          )
          mesh = join_meshes_as_scene([mesh1, mesh2, mesh3, mesh4])
  
          output = renderer(mesh)[0, ..., :3].cpu()
          output1 = renderer(mesh1)[0, ..., :3].cpu()
          output2 = renderer(mesh2)[0, ..., :3].cpu()
          output3 = renderer(mesh3)[0, ..., :3].cpu()
          # The background color is white and the objects do not overlap, so we can
          # predict the merged image by taking the minimum over every channel
          merged = torch.min(torch.min(output1, output2), output3)
  
          image_ref = load_rgb_image(
              f"test_joinuvs{i}_{rasterizer_type.__name__}_final.png",
              DATA_DIR,
          )
          map_ref = load_rgb_image(f"test_joinuvs{i}_map.png", DATA_DIR)
  
          if DEBUG:
              Image.fromarray(
                  (output.numpy() * 255).astype(np.uint8)
              ).save(
                  DATA_DIR
                  / f"DEBUG_test_joinuvs{i}_{rasterizer_type.__name__}_final.png"
              )
              Image.fromarray(
                  (merged.numpy() * 255).astype(np.uint8)
              ).save(
                  DATA_DIR
                  / f"DEBUG_test_joinuvs{i}_{rasterizer_type.__name__}_merged.png"
              )
  
              Image.fromarray(
                  (output1.numpy() * 255).astype(np.uint8)
              ).save(
                  DATA_DIR
                  / f"DEBUG_test_joinuvs{i}_{rasterizer_type.__name__}_1.png"
              )
              Image.fromarray(
                  (output2.numpy() * 255).astype(np.uint8)
              ).save(
                  DATA_DIR
                  / f"DEBUG_test_joinuvs{i}_{rasterizer_type.__name__}_2.png"
              )
              Image.fromarray(
                  (output3.numpy() * 255).astype(np.uint8)
              ).save(
                  DATA_DIR
                  / f"DEBUG_test_joinuvs{i}_{rasterizer_type.__name__}_3.png"
              )
              Image.fromarray(
                  (
                      mesh.textures.maps_padded()[0].cpu().numpy() * 255
                  ).astype(np.uint8)
              ).save(DATA_DIR / f"DEBUG_test_joinuvs{i}_map.png")
              Image.fromarray(
                  (
                      mesh2.textures.maps_padded()[0].cpu().numpy()
                      * 255
                  ).astype(np.uint8)
              ).save(DATA_DIR / f"DEBUG_test_joinuvs{i}_map2.png")
              Image.fromarray(
                  (
                      mesh3.textures.maps_padded()[0].cpu().numpy()
                      * 255
                  ).astype(np.uint8)
              ).save(DATA_DIR / f"DEBUG_test_joinuvs{i}_map3.png")
  
          self.assertClose(output, merged, atol=0.005)
          self.assertClose(output, image_ref, atol=0.005)
          self.assertClose(
              mesh.textures.maps_padded()[0].cpu(), map_ref, atol=0.05
          )
  
imports: import os
  import unittest
  from collections import namedtuple
  from itertools import product
  import numpy
  import torch
  from PIL import Image
  from pytorch3d.io import load_obj, load_objs_as_meshes
  from pytorch3d.renderer import AmbientLights, FoVOrthographicCameras, FoVPerspectiveCameras, look_at_view_transform, Materials, MeshRasterizer, MeshRenderer, MeshRendererWithFragments, OrthographicCameras, PerspectiveCameras, PointLights, RasterizationSettings, TexturesAtlas, TexturesUV, TexturesVertex
  from pytorch3d.renderer.fisheyecameras import FishEyeCameras
  from pytorch3d.renderer.mesh.shader import BlendParams, HardFlatShader, HardGouraudShader, HardPhongShader, SoftPhongShader, SoftSilhouetteShader, SplatterPhongShader, TexturedSoftPhongShader
  from pytorch3d.renderer.opengl import MeshRasterizerOpenGL
  from pytorch3d.structures.meshes import join_meshes_as_batch, join_meshes_as_scene, Meshes
  from pytorch3d.utils.ico_sphere import ico_sphere
  from pytorch3d.utils.torus import torus
  from .common_testing import get_pytorch3d_dir, get_tests_dir, load_rgb_image, TestCaseMixin
label_desc: Use image node_id 15 for calling the TestRenderMeshes obj's underlying member method code with example usage: obj._join_uvs(rasterizer_type) without return types