Making an SDF Dataset for ShapeNet
The code below is a simple script for making a dataset of signed distance functions for the ShapeNet Dataset. To get started, first make an account and download ShapeNet here. Once you have downloaded ShapeNet, run the script below from the root of the dataset. It loads each ShapeNet model, which may be non-watertight and non-manifold, computes a watertight and manifold mesh for that object and generates 100k points in the volume around the shape along with their corresponding signed distances. It also generates 100k points on the surface of the shape with surface normals at those points.
import os
import numpy as np
import point_cloud_utils as pcu
# Path to the bench category as an example
category_path = "./02828884"
# Resolution used to convert shapes to watertight manifolds
# Higher value means better quality and slower
manifold_resolution = 20_000
# Number of points in the volume to sample around the shape
num_vol_pts = 100_000
# Number of points on the surface to sample
num_surf_pts = 100_000
for model_path in os.listdir(category_path):
v, f = pcu.load_mesh_vf(os.path.join(category_path, model_path, "model.obj"))
# Convert mesh to watertight manifold
vm, fm = pcu.make_mesh_watertight(v, f, manifold_resolution)
nm = pcu.estimate_mesh_vertex_normals(vm, fm) # Compute vertex normals for watertight mesh
# Generate random points in the volume around the shape
# NOTE: ShapeNet shapes are normalized within [-0.5, 0.5]^3
p_vol = (np.random.rand(num_vol_pts, 3) - 0.5) * 1.1
# Comput the SDF of the random points
sdf, _, _ = pcu.signed_distance_to_mesh(p_vol, vm, fm)
# Sample points on the surface as face ids and barycentric coordinates
fid_surf, bc_surf = pcu.sample_mesh_random(vm, fm, num_surf_pts)
# Compute 3D coordinates and normals of surface samples
p_surf = pcu.interpolate_barycentric_coords(fm, fid_surf, bc_surf, vm)
n_surf = pcu.interpolate_barycentric_coords(fm, fid_surf, bc_surf, nm)
# Save volume points + SDF and surface points + normals
# Load using np.load()
npz_path = os.path.join(category_path, model_path, "samples.npz")
np.savez(npz_path, p_vol=p_vol, sdf_vol=sdf, p_surf=p_surf, n_surf=n_surf)
# Save the watertight mesh
watertight_mesh_path = os.path.join(category_math, model_path, "model_watertight.obj")
pcu.save_mesh_vfn(watertight_mesh_path, vm, fm, nm)