def _test_face_areas_normals_helper(self, device, dtype=torch.float32): """ Check the results from face_areas cuda/cpp and PyTorch implementation are the same. """ meshes = self.init_meshes(10, 200, 400, device=device) # make them leaf nodes verts = meshes.verts_packed().detach().clone().to(dtype) verts.requires_grad = True faces = meshes.faces_packed().detach().clone() # forward areas, normals = mesh_face_areas_normals(verts, faces) verts_torch = verts.detach().clone().to(dtype) verts_torch.requires_grad = True faces_torch = faces.detach().clone() (areas_torch, normals_torch) = TestFaceAreasNormals.face_areas_normals_python( verts_torch, faces_torch) self.assertClose(areas_torch, areas, atol=1e-7) # normals get normalized by area thus sensitivity increases as areas # in our tests can be arbitrarily small. Thus we compare normals after # multiplying with areas unnormals = normals * areas.view(-1, 1) unnormals_torch = normals_torch * areas_torch.view(-1, 1) self.assertClose(unnormals_torch, unnormals, atol=1e-6) # backward grad_areas = torch.rand(areas.shape, device=device, dtype=dtype) grad_normals = torch.rand(normals.shape, device=device, dtype=dtype) areas.backward((grad_areas, grad_normals)) grad_verts = verts.grad areas_torch.backward((grad_areas, grad_normals)) grad_verts_torch = verts_torch.grad self.assertClose(grad_verts_torch, grad_verts, atol=1e-6)
def face_areas_normals(): mesh_face_areas_normals(verts, faces) torch.cuda.synchronize()