From 8ec14f2615b655e5861aa6b39fd9a5161dcd89a3 Mon Sep 17 00:00:00 2001 From: Narinder Singh <11069888+NarinderS@users.noreply.github.com> Date: Tue, 13 Feb 2024 15:34:45 -0700 Subject: [PATCH 1/5] Fix loading of normals in obj_loader.h --- src/common/obj_loader.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/common/obj_loader.h b/src/common/obj_loader.h index 2944162..8984c88 100644 --- a/src/common/obj_loader.h +++ b/src/common/obj_loader.h @@ -73,12 +73,6 @@ std::unordered_map load_mesh_obj(const std::strin v(i, 1) = attrib.vertices[3*i+1]; v(i, 2) = attrib.vertices[3*i+2]; - if (attrib.normals.size() > 0) { - n(i, 0) = attrib.normals[3*i+0]; - n(i, 1) = attrib.normals[3*i+1]; - n(i, 2) = attrib.normals[3*i+2]; - } - if (attrib.texcoords.size() > 0) { tc(i, 0) = attrib.texcoords[2*i+0]; tc(i, 1) = attrib.texcoords[2*i+1]; @@ -131,6 +125,9 @@ std::unordered_map load_mesh_obj(const std::strin for (size_t vidx = 0; vidx < num_vertices_in_face; vidx += 1) { tinyobj::index_t idx = shapes[sidx].mesh.indices[index_offset + vidx]; f(f_offset, vidx) = size_t(idx.vertex_index); + n(idx.vertex_index, 0) = attrib.normals[3*idx.normal_index+0]; + n(idx.vertex_index, 1) = attrib.normals[3*idx.normal_index+1]; + n(idx.vertex_index, 2) = attrib.normals[3*idx.normal_index+2]; } if (shapes[sidx].mesh.material_ids.size() > 0) { From b95da45ead070784b13639a277fe3e7f141b37f0 Mon Sep 17 00:00:00 2001 From: Narinder Singh <11069888+NarinderS@users.noreply.github.com> Date: Tue, 13 Feb 2024 16:37:25 -0700 Subject: [PATCH 2/5] Add check for presence of normals --- src/common/obj_loader.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/common/obj_loader.h b/src/common/obj_loader.h index 8984c88..d954485 100644 --- a/src/common/obj_loader.h +++ b/src/common/obj_loader.h @@ -110,6 +110,7 @@ std::unordered_map load_mesh_obj(const std::strin } f.resize(total_faces, 3); mat_ids.resize(total_mat_ids, 1); + bool normals_present = attrib.normals.size() > 0; size_t f_offset = 0; for (size_t sidx = 0; sidx < shapes.size(); sidx += 1) { // Loop over shapes @@ -125,9 +126,11 @@ std::unordered_map load_mesh_obj(const std::strin for (size_t vidx = 0; vidx < num_vertices_in_face; vidx += 1) { tinyobj::index_t idx = shapes[sidx].mesh.indices[index_offset + vidx]; f(f_offset, vidx) = size_t(idx.vertex_index); - n(idx.vertex_index, 0) = attrib.normals[3*idx.normal_index+0]; - n(idx.vertex_index, 1) = attrib.normals[3*idx.normal_index+1]; - n(idx.vertex_index, 2) = attrib.normals[3*idx.normal_index+2]; + if (normals_present) { + n(idx.vertex_index, 0) = attrib.normals[3*idx.normal_index+0]; + n(idx.vertex_index, 1) = attrib.normals[3*idx.normal_index+1]; + n(idx.vertex_index, 2) = attrib.normals[3*idx.normal_index+2]; + } } if (shapes[sidx].mesh.material_ids.size() > 0) { From 0198deb93941afe4a45a41d592a0a7336df84681 Mon Sep 17 00:00:00 2001 From: Francis Williams Date: Fri, 6 Sep 2024 16:15:03 -0400 Subject: [PATCH 3/5] Update obj_loader.h --- src/common/obj_loader.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/common/obj_loader.h b/src/common/obj_loader.h index d954485..3a28097 100644 --- a/src/common/obj_loader.h +++ b/src/common/obj_loader.h @@ -358,5 +358,4 @@ void save_mesh_obj(std::string filename, outstream << std::endl; } } - -} \ No newline at end of file +} From 8588cb9c3aa8cd0dad9b7c3a82ce60cf92851153 Mon Sep 17 00:00:00 2001 From: Narinder Singh <11069888+NarinderS@users.noreply.github.com> Date: Sun, 13 Oct 2024 20:21:14 -0600 Subject: [PATCH 4/5] Fixed UV loading for objs with repeated UV indices --- src/common/obj_loader.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/common/obj_loader.h b/src/common/obj_loader.h index 3a28097..f92254a 100644 --- a/src/common/obj_loader.h +++ b/src/common/obj_loader.h @@ -73,16 +73,6 @@ std::unordered_map load_mesh_obj(const std::strin v(i, 1) = attrib.vertices[3*i+1]; v(i, 2) = attrib.vertices[3*i+2]; - if (attrib.texcoords.size() > 0) { - tc(i, 0) = attrib.texcoords[2*i+0]; - tc(i, 1) = attrib.texcoords[2*i+1]; - if (attrib.texcoord_ws.size() > 0) { - tc(i, 2) = attrib.texcoord_ws[i]; - } else { - tc(i, 2) = 0; - } - } - if (attrib.colors.size() > 0) { c(i, 0) = attrib.colors[3*i+0]; c(i, 1) = attrib.colors[3*i+1]; @@ -111,6 +101,8 @@ std::unordered_map load_mesh_obj(const std::strin f.resize(total_faces, 3); mat_ids.resize(total_mat_ids, 1); bool normals_present = attrib.normals.size() > 0; + bool texcoords_present = attrib.texcoords.size() > 0; + bool texcoord_ws_present = attrib.texcoord_ws.size() > 0; size_t f_offset = 0; for (size_t sidx = 0; sidx < shapes.size(); sidx += 1) { // Loop over shapes @@ -131,6 +123,15 @@ std::unordered_map load_mesh_obj(const std::strin n(idx.vertex_index, 1) = attrib.normals[3*idx.normal_index+1]; n(idx.vertex_index, 2) = attrib.normals[3*idx.normal_index+2]; } + if (texcoords_present) { + tc(idx.vertex_index, 0) = attrib.texcoords[2*idx.texcoord_index+0]; + tc(idx.vertex_index, 1) = attrib.texcoords[2*idx.texcoord_index+1]; + if (texcoord_ws_present) { + tc(idx.vertex_index, 2) = attrib.texcoord_ws[idx.texcoord_index]; + } else { + tc(idx.vertex_index, 2) = 0; + } + } } if (shapes[sidx].mesh.material_ids.size() > 0) { From d119c4345cb8898b707829772e062f85b685e57c Mon Sep 17 00:00:00 2001 From: Narinder Singh <11069888+NarinderS@users.noreply.github.com> Date: Sun, 13 Oct 2024 20:21:30 -0600 Subject: [PATCH 5/5] Added unit test --- data/simple.obj | 8 ++++++++ tests/test_examples.py | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 data/simple.obj diff --git a/data/simple.obj b/data/simple.obj new file mode 100644 index 0000000..5754f7c --- /dev/null +++ b/data/simple.obj @@ -0,0 +1,8 @@ +o Plane +v 0.0 0.0 0.0 1.0 0.0 0.0 +v 1.0 1.0 0.0 0.0 1.0 0.0 +v 1.0 -1.0 0.0 0.0 0.0 1.0 +vn 0.0 0.0 1.0 +vt 1.0 0.0 +s 0 +f 2/1/1 1/1/1 3/1/1 \ No newline at end of file diff --git a/tests/test_examples.py b/tests/test_examples.py index d73ba5c..b0e24b8 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -762,5 +762,31 @@ def test_orient_mesh_faces(self): self.assertTrue(np.all(f_oriented == f)) self.assertTrue(np.all(f_comp_ids == 0)) + def test_obj_loading(self): + import point_cloud_utils as pcu + import numpy as np + + mesh_path = os.path.join(self.test_path, "simple.obj") + mesh = pcu.load_triangle_mesh(mesh_path) + vn_true = np.array([ + [0,0,1], + [0,0,1], + [0,0,1]], dtype=np.float32) + uv_true = np.array([ + [1,0,0], + [1,0,0], + [1,0,0]], dtype=np.float32) + colors_true = np.array([ + [1,0,0,1], + [0,1,0,1], + [0,0,1,1]], dtype=np.float32) + + self.assertEqual(mesh.v.shape, (3, 3)) + self.assertEqual(mesh.f.shape, (3,)) + self.assertEqual(mesh.vn.shape, (3, 3)) + self.assertTrue(np.allclose(mesh.vn, vn_true)) + self.assertTrue(np.allclose(mesh.vertex_data.texcoords, uv_true)) + self.assertTrue(np.allclose(mesh.vc, colors_true)) + if __name__ == '__main__': unittest.main()