From eb517dd70b20c8431a1cfc46e47b4c5c78529c5b Mon Sep 17 00:00:00 2001 From: Amitav Baruah Date: Thu, 10 Sep 2020 12:52:13 -0700 Subject: [PATCH] Fix look_at corner case Summary: When the camera is vertically oriented, calculating the look_at x-axis (also known as the "right" vector) does not succeed, resulting in the x-axis being placed at the origin. Adds a check to correctly calculate the x-axis if this case occurs. Reviewed By: nikhilaravi, sbranson Differential Revision: D23511859 fbshipit-source-id: ee5145cdbecdbe2f7c7d288588bd0899480cb327 --- pytorch3d/renderer/cameras.py | 6 ++++++ tests/test_cameras.py | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/pytorch3d/renderer/cameras.py b/pytorch3d/renderer/cameras.py index 8ea5d4d3..3549b355 100644 --- a/pytorch3d/renderer/cameras.py +++ b/pytorch3d/renderer/cameras.py @@ -1226,6 +1226,12 @@ def look_at_rotation( z_axis = F.normalize(at - camera_position, eps=1e-5) x_axis = F.normalize(torch.cross(up, z_axis, dim=1), eps=1e-5) y_axis = F.normalize(torch.cross(z_axis, x_axis, dim=1), eps=1e-5) + is_close = torch.isclose(x_axis, torch.tensor(0.0), atol=5e-3).all( + dim=1, keepdim=True + ) + if is_close.any(): + replacement = F.normalize(torch.cross(y_axis, z_axis, dim=1), eps=1e-5) + x_axis = torch.where(is_close, replacement, x_axis) R = torch.cat((x_axis[:, None, :], y_axis[:, None, :], z_axis[:, None, :]), dim=1) return R.transpose(1, 2) diff --git a/tests/test_cameras.py b/tests/test_cameras.py index b74cd74d..298301d2 100644 --- a/tests/test_cameras.py +++ b/tests/test_cameras.py @@ -433,6 +433,20 @@ class TestCameraHelpers(TestCaseMixin, unittest.TestCase): RT = get_world_to_view_transform(R=R, T=T) self.assertTrue(isinstance(RT, Transform3d)) + def test_look_at_view_transform_corner_case(self): + dist = 2.7 + elev = 90 + azim = 90 + expected_position = torch.tensor([0.0, 2.7, 0.0], dtype=torch.float32).view( + 1, 3 + ) + position = camera_position_from_spherical_angles(dist, elev, azim) + self.assertClose(position, expected_position, atol=2e-7) + R, _ = look_at_view_transform(eye=position) + x_axis = R[:, :, 0] + expected_x_axis = torch.tensor([0.0, 0.0, -1.0], dtype=torch.float32).view(1, 3) + self.assertClose(x_axis, expected_x_axis, atol=5e-3) + class TestCamerasCommon(TestCaseMixin, unittest.TestCase): def test_view_transform_class_method(self):