docstr: Check outputs of sampling are correct for different meshes.
  For an ico_sphere, the sampled vertices should lie on a unit sphere.
  For an empty mesh, the samples and normals should be 0.
docstr_tok: ["Check","outputs","of","sampling","are","correct","for","different","meshes",".","For","an","ico_sphere",",","the","sampled","vertices","should","lie","on","a","unit","sphere",".","For","an","empty","mesh",",","the","samples","and","normals","should","be","0","."]
code: def test_sampling_output(self):
      """
      Check outputs of sampling are correct for different meshes.
      For an ico_sphere, the sampled vertices should lie on a unit sphere.
      For an empty mesh, the samples and normals should be 0.
      """
      device = get_random_cuda_device()
  
      # Unit simplex.
      verts_pyramid = torch.tensor(
          [
              [0.0, 0.0, 0.0],
              [1.0, 0.0, 0.0],
              [0.0, 1.0, 0.0],
              [0.0, 0.0, 1.0],
          ],
          dtype=torch.float32,
          device=device,
      )
      faces_pyramid = torch.tensor(
          [[0, 1, 2], [0, 2, 3], [0, 1, 3], [1, 2, 3]],
          dtype=torch.int64,
          device=device,
      )
      sphere_mesh = ico_sphere(9, device)
      verts_sphere, faces_sphere = sphere_mesh.get_mesh_verts_faces(0)
      verts_empty = torch.tensor([], dtype=torch.float32, device=device)
      faces_empty = torch.tensor([], dtype=torch.int64, device=device)
      num_samples = 10
      meshes = Meshes(
          verts=[verts_empty, verts_sphere, verts_pyramid],
          faces=[faces_empty, faces_sphere, faces_pyramid],
      )
      samples, normals = sample_points_from_meshes(
          meshes, num_samples=num_samples, return_normals=True
      )
      samples = samples.cpu()
      normals = normals.cpu()
  
      self.assertEqual(samples.shape, (3, num_samples, 3))
      self.assertEqual(normals.shape, (3, num_samples, 3))
  
      # Empty meshes: should have all zeros for samples and normals.
      self.assertClose(samples[0, :], torch.zeros((num_samples, 3)))
      self.assertClose(normals[0, :], torch.zeros((num_samples, 3)))
  
      # Sphere: points should have radius 1.
      x, y, z = samples[1, :].unbind(1)
      radius = torch.sqrt(x**2 + y**2 + z**2)
  
      self.assertClose(radius, torch.ones(num_samples))
  
      # Pyramid: points shoudl lie on one of the faces.
      pyramid_verts = samples[2, :]
      pyramid_normals = normals[2, :]
  
      self.assertClose(
          pyramid_verts.lt(1).float(), torch.ones_like(pyramid_verts)
      )
      self.assertClose(
          (pyramid_verts >= 0).float(), torch.ones_like(pyramid_verts)
      )
  
      # Face 1: z = 0,  x + y <= 1, normals = (0, 0, 1).
      face_1_idxs = pyramid_verts[:, 2] == 0
      face_1_verts, face_1_normals = (
          pyramid_verts[face_1_idxs, :],
          pyramid_normals[face_1_idxs, :],
      )
      self.assertTrue(
          torch.all((face_1_verts[:, 0] + face_1_verts[:, 1]) <= 1)
      )
      self.assertClose(
          face_1_normals,
          torch.tensor([0, 0, 1], dtype=torch.float32).expand(
              face_1_normals.size()
          ),
      )
  
      # Face 2: x = 0,  z + y <= 1, normals = (1, 0, 0).
      face_2_idxs = pyramid_verts[:, 0] == 0
      face_2_verts, face_2_normals = (
          pyramid_verts[face_2_idxs, :],
          pyramid_normals[face_2_idxs, :],
      )
      self.assertTrue(
          torch.all((face_2_verts[:, 1] + face_2_verts[:, 2]) <= 1)
      )
      self.assertClose(
          face_2_normals,
          torch.tensor([1, 0, 0], dtype=torch.float32).expand(
              face_2_normals.size()
          ),
      )
  
      # Face 3: y = 0, x + z <= 1, normals = (0, -1, 0).
      face_3_idxs = pyramid_verts[:, 1] == 0
      face_3_verts, face_3_normals = (
          pyramid_verts[face_3_idxs, :],
          pyramid_normals[face_3_idxs, :],
      )
      self.assertTrue(
          torch.all((face_3_verts[:, 0] + face_3_verts[:, 2]) <= 1)
      )
      self.assertClose(
          face_3_normals,
          torch.tensor([0, -1, 0], dtype=torch.float32).expand(
              face_3_normals.size()
          ),
      )
  
      # Face 4: x + y + z = 1, normals = (1, 1, 1)/sqrt(3).
      face_4_idxs = pyramid_verts.gt(0).all(1)
      face_4_verts, face_4_normals = (
          pyramid_verts[face_4_idxs, :],
          pyramid_normals[face_4_idxs, :],
      )
      self.assertClose(
          face_4_verts.sum(1), torch.ones(face_4_verts.size(0))
      )
      self.assertClose(
          face_4_normals,
          (
              torch.tensor([1, 1, 1], dtype=torch.float32)
              / torch.sqrt(torch.tensor(3, dtype=torch.float32))
          ).expand(face_4_normals.size()),
      )
  
imports: import unittest
  import numpy
  import torch
  from PIL import Image
  from pytorch3d.io import load_objs_as_meshes
  from pytorch3d.ops import sample_points_from_meshes
  from pytorch3d.renderer import TexturesVertex
  from pytorch3d.renderer.cameras import FoVPerspectiveCameras, look_at_view_transform
  from pytorch3d.renderer.mesh.rasterize_meshes import barycentric_coordinates
  from pytorch3d.renderer.points import NormWeightedCompositor, PointsRasterizationSettings, PointsRasterizer, PointsRenderer
  from pytorch3d.structures import Meshes, Pointclouds
  from pytorch3d.utils.ico_sphere import ico_sphere
  from .common_testing import get_pytorch3d_dir, get_random_cuda_device, get_tests_dir, TestCaseMixin
label_desc: Use image node_id 3 for calling the TestSamplePoints obj's underlying member method code with example usage: obj.test_sampling_output() without return types