0
votes

I have a given 3D mesh which is constructed by taking a set of random points and finding the convex hull of those points. I then use open3d and trimesh to convert the conex hull into a mesh. I want to know how I can convert this mesh or the convex hull itself into a filled boolean voxel grid.

I can use trimesh to get a voxel grid of some sort but it seems the insides are hollow. I want a boolean voxel grid which gives true for the volume inside the convex hull and false otherwise.

2

2 Answers

1
votes

Simply rasterize your convex polygon volume ...

  1. compute any inside point c

    for convex hull its enough to compute avg point so sum all n points together an divide by n

  2. compute per face normals

    each triangle face has 3 points p0,p1,p2 so

    nor = cross( p1-p0 , p2-p0 );
    

    and chose direction so it points out of the convex hull so:

    if ( dot( p0-c , nor ) < 0) nor = -nor;
    
  3. loop through all voxels

    so 3 nested for loops going through your grid. Lets call the actual iterated point q

  4. test inside convex hull

    the q is inside your convex hull if all dot products between q-face_point and face_normal is negative or zero... So loop through all triangles/faces and test... after that either fill the voxel or not ...

If you want something faster (in case you got too many triangles) there are ways like:

  • Rasterize the triangles and floodfill
  • Tetrahedronize volume and rasterize each tetrahedron separately
  • render depth maps from 6 sides of outscribed cube and infill
1
votes

So I figured out a simple solution which can be implemented using trimmesh. The idea is to generate a large set of coordinates and query the mesh to determine if the coordinate is within the mesh/convex hull. If the coordinate is within the mesh it is indicated in the grid as 1 and 0 otherwise. res is an array that determines the resolution along x,y,z axis. A higher resolution provides much better representation of the mesh.

x, y, z = np.indices((res[0], res[1], res[2]))
total_voxels = np.product(res)
coords = np.concatenate((np.reshape(x/res[0], [total_voxels, 1]),       
         np.reshape(y/res[1], [total_voxels, 1]),
         np.reshape(z/res[2], [total_voxels, 1])), axis=1)
out = mesh.contains(coords)
voxel = np.reshape(out, res)

Still leaving this open just in case someone has a better solution.