Reputation: 31
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):
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
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