marian42 / mesh_to_sdf

Calculate signed distance fields for arbitrary meshes
https://pypi.org/project/mesh-to-sdf/
MIT License
991 stars 107 forks source link

How to get normals together with points and sdf? #4

Closed wangzheallen closed 4 years ago

wangzheallen commented 4 years ago

I can use mesh_to_sdf.sample_sdf_near_surface like:

points, sdf = mesh_to_sdf.sample_sdf_near_surface(mesh, number_of_points=SDF_CLOUD_SAMPLE_SIZE, surface_point_method='scan', sign_method='normal', scan_count=100, scan_resolution=400, sample_point_count=10000000, normal_sample_count=11, min_size=0)`

But miss the normal for the points? How can I get the normals?

Thanks!

marian42 commented 4 years ago

You could try to get the closest surface using the surface point cloud, take the vector from each point to the closest surface point and normalize it.

Here is an example (I haven't tested it):

point_cloud = mesh_to_sdf.get_surface_point_cloud(mesh, surface_point_method='scan', bounding_radius=None, scan_count=100, scan_resolution=400, sample_point_count=10000000, calculate_normals=True)

points, sdf = point_cloud.get_sdf_in_batches(query_points, use_depth_buffer=False)

distances, indices = point_cloud.kd_tree.query(points, k=1)

closest_points = point_cloud.points[indices]
direction_from_surface = closest_points - points
normals = direction_from_surface / np.linalg.norm(direction_from_surface)

The kd tree query and the direction_from_surface are also calculated by get_sdf_in_batches, so you could modify that function to return these values and this would make it faster.

wangzheallen commented 4 years ago

Thanks for the detailed reply! :-) I assume query points and sdf can be calculated directly from query_points, sdf = sample_sdf_near_surface(mesh, number_of_points=number_of_points) and sample_sdf_near_surface should sample points both near surface and uniformly in the scene. May I ask why the normal is in opposite direction? do we need direction_from_surface = points - closest_points ??

marian42 commented 4 years ago

You're right, it should be direction_from_surface = points - closest_points. However, that is only for points outside the object. For points inside, they need to be inverted. You could achieve this by multiplying with the sign of the SDF.