Blake Havens
Blake Havens

Reputation: 31

Generating Uniform Point Cloud with Surface Normals from Meshes

I need help to create some kind of way to generate very uniform (ie. grid-like) point clouds for any mesh provided. Each of these points do require surface normal data.

Here is what I've tried:

Open 3D: I imported my mesh into Open3D and used the voxelization downscaling. This almost worked as I wanted. Unfortunately, it generates fairly undistributed clouds. Here is an example of a Z-oriented slice of the point cloud (voxelized point cloud):

Z slice of generated point cloud

This method was also fairly expensive, computationally speaking. I had to randomly sample the object thousands of times in order to even generate the point cloud, and still left with 'bald' spots in the data. Here is how I did it:

N = 50000
pcd = mesh.sample_points_poisson_disk(N)
pcd.colors = o3d.utility.Vector3dVector(np.random.uniform(0, 1, size=(N, 3)))

downpcd = pcd.voxel_down_sample(voxel_size=0.05)
downpcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30))
downpcd.orient_normals_consistent_tangent_plane(100)

Trimesh, PyVista: These could generate very nice voxel representations, however, as far as I am aware, they do not support finding surface normals at a point.

PyBullet: This might seem weird being here, but I was previously using this for a control system and used its ray casting system. I simply cast rays in a sphere around the object, which worked very well for generating point clouds. However, since PyBullet is no longer being used, I would like to avoid using this hefty library.

Are there any libraries or references I should check out to solve this? I've been itching my head for a while. I think having a raycasting library would be the best case given my requirements, but there must be lighter-weight ones than pybullet.

Please note that I do require the surface normals at each specific point cloud point.

Thank you!

Upvotes: 0

Views: 675

Answers (1)

el_grezeq
el_grezeq

Reputation: 133

It is quite straightforward to generate a pointcloud with normals from a mesh (points are generated from faces, faces have normals).

Using trimesh:

import trimesh

mesh_file = "my_mesh_file.ext"
N = 50000

mesh = trimesh.load(mesh_file)
points, face_index = mesh.sample(N, return_index=True) # weighted by face area by default
normals = mesh.face_normals[face_index]

By default, it takes face areas into account (i.e., the larger the face, the more points on it), so you should have a quite homogeneous pointcloud already. But nothing prevents you from building a voxel grid afterwards.

Upvotes: 0

Related Questions