diff --git a/pytorch3d/io/obj_io.py b/pytorch3d/io/obj_io.py index 9e2e2e7f..36b6ff53 100644 --- a/pytorch3d/io/obj_io.py +++ b/pytorch3d/io/obj_io.py @@ -472,26 +472,26 @@ def _parse_obj(f, data_dir: str): materials_idx = len(material_names) - 1 else: materials_idx = material_names.index(material_name) - elif line.startswith("v "): # Line is a vertex. + elif tokens[:1] == ["v"]: # Line is a vertex. vert = [float(x) for x in tokens[1:4]] if len(vert) != 3: msg = "Vertex %s does not have 3 values. Line: %s" raise ValueError(msg % (str(vert), str(line))) verts.append(vert) - elif line.startswith("vt "): # Line is a texture. + elif tokens[:1] == ["vt"]: # Line is a texture. tx = [float(x) for x in tokens[1:3]] if len(tx) != 2: raise ValueError( "Texture %s does not have 2 values. Line: %s" % (str(tx), str(line)) ) verts_uvs.append(tx) - elif line.startswith("vn "): # Line is a normal. + elif tokens[:1] == ["vn"]: # Line is a normal. norm = [float(x) for x in tokens[1:4]] if len(norm) != 3: msg = "Normal %s does not have 3 values. Line: %s" raise ValueError(msg % (str(norm), str(line))) normals.append(norm) - elif line.startswith("f "): # Line is a face. + elif tokens[:1] == ["f"]: # Line is a face. # Update face properties info. _parse_face( line, diff --git a/tests/test_io_obj.py b/tests/test_io_obj.py index eb379ea5..1d483640 100644 --- a/tests/test_io_obj.py +++ b/tests/test_io_obj.py @@ -319,6 +319,29 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): self.assertTrue(materials is None) self.assertTrue(tex_maps is None) + def test_load_obj_tab_separated(self): + # Tabs are whitespace too, including between the keyword and the values. + obj_file = "\n".join( + [ + "v\t0.1\t0.2\t0.3", + "v 0.2 0.3 0.4", + "v\t0.3 0.4 0.5", + "vt\t0.5\t0.5", + "vn\t0.0\t0.0\t1.0", + "f\t1/1/1\t2/1/1\t3/1/1", + ] + ) + verts, faces, aux = load_obj(StringIO(obj_file)) + expected_verts = torch.tensor( + [[0.1, 0.2, 0.3], [0.2, 0.3, 0.4], [0.3, 0.4, 0.5]], dtype=torch.float32 + ) + self.assertClose(verts, expected_verts) + self.assertClose(faces.verts_idx, torch.tensor([[0, 1, 2]])) + self.assertClose(faces.textures_idx, torch.tensor([[0, 0, 0]])) + self.assertClose(faces.normals_idx, torch.tensor([[0, 0, 0]])) + self.assertClose(aux.verts_uvs, torch.tensor([[0.5, 0.5]])) + self.assertClose(aux.normals, torch.tensor([[0.0, 0.0, 1.0]])) + def test_load_obj_error_textures(self): obj_file = "\n".join(["vt 0.1"]) with NamedTemporaryFile(mode="w", suffix=".obj") as f: