Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix obj loader #6047

Merged
merged 9 commits into from
May 28, 2024
Merged

Fix obj loader #6047

merged 9 commits into from
May 28, 2024

Conversation

Olli1080
Copy link
Contributor

This pull request enables the obj loader to load files which do not use exactly one normal per vertex and also allow for loading of files where normal indices are used for multiple vertices. (e.g. obj files exported by blender).

To do so it accumulates the normals used per vertex over the faces and computes normals for the vertices.

Remove restriction that normals are per vertex
Files without normals now created errors
Face indices would have been first vertex index for all vertices
@mvieth
Copy link
Member

mvieth commented May 21, 2024

Hi, thanks for the fix, I would like to ask two things: firstly, could you post a file where the problem occurs, so that I can understand the problem better? And secondly, you have changed a lot of formatting (most importantly, indentation), which makes the changes very unclear and difficult to review. Could you revert all formatting changes, please?

@mvieth mvieth added module: io changelog: fix Meta-information for changelog generation labels May 21, 2024
@Olli1080
Copy link
Contributor Author

Github doesn't allow me to upload the file directly as an obj file so i attach it as a zip.
franka_link0.zip
This file was created by importing a dae file from https://github.com/frankaemika/franka_ros/tree/develop/franka_description/meshes/visual and exporting it as a obj file using blender.
In the file every vertex has more than one normal assigned but some normals where used for multiple faces as well (i guess deduplication efforts by blender).
The previous code assumed that "vn" is 1:1 for vertices.

Sorry for the formatting issues i'll fix them and push the changes.

@Olli1080
Copy link
Contributor Author

The diff should now only cover the relevant lines.

@mvieth
Copy link
Member

mvieth commented May 24, 2024

Thank you, the diff is much clearer now. And I think your solution of storing normals and averaging them per vertex makes sense.
It would be good if we could create a test for this fixed behaviour. There is one at https://github.com/PointCloudLibrary/pcl/blob/master/test/io/test_io.cpp#L1038 for reading a PCLPointCloud2 from an obj file, but that does not test the values of x, y, z, or the normal. Here is an idea:

pcl::PointCloud<pcl::PointNormal> cloud;
pcl::fromPCLPointCloud2(blob, cloud);
EXPECT_EQ(cloud.size(), 8);
for(const auto& point: cloud) {
  Eigen::Vector3f expected_normal(point.x, point.y, point.z);
  expected_normal.normalize();
  EXPECT_NEAR(expected_normal.x(), point.x, 1e-4);
  EXPECT_NEAR(expected_normal.y(), point.y, 1e-4);
  EXPECT_NEAR(expected_normal.z(), point.z, 1e-4);
}

Which basically tests whether the vector from the cube center to the point is the same as the point normal. If you think this is good, would you be willing to add this to this pull request?

I am also wondering about the use of normals in the obj file format, maybe you have an intuition about this. In the file you uploaded, for each face, all vertices have the same normal (the normal of the face). If this is the intended use of the normals, it is strange why the creators of the file format chose to have the normals specified per vertex (redundant) instead of per face (e.g. f <normal index> <v1>/<vt1> <v2>/<vt2> ...). Another possibility is that it is intended to be the normal of the individual vertex, so that the normals of the different vertices of one face may differ, but if the coordinate indices of two vertices (of different faces) are the same, then the normal indices must also be the same. PCL currently writes obj files following this second logic. But I am wondering what programs that read obj files usually expect, what do you think? I tried googling but did not find a definitive answer so far.

@Olli1080
Copy link
Contributor Author

I integrated the suggested test into the existing one.
From what i've seen the normals are sometimes interpreted as vertex normals but other times as face normals (hence same normal for all vertices of a face).
These links highlight some of the oddities:
https://www.reddit.com/r/GraphicsProgramming/comments/173hfox/are_vn_in_obj_files_really_face_normals/
https://stackoverflow.com/questions/58535803/what-does-the-normals-vn-in-wavefront-obj-files-represent

The obj file i provided also has one more irregularity e.g. in line 3512 it reuses vn 1227 in (i guess) an attempt to compress the file by deduplication.
I don't think the approach of pcl to saving obj normals per vertex is wrong as (from what i've seen) differing shading types are somewhat ignored.

Copy link
Member

@mvieth mvieth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again for the pull request and the background information!

@mvieth mvieth merged commit ca49c63 into PointCloudLibrary:master May 28, 2024
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changelog: fix Meta-information for changelog generation module: io
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants