Skip to main content

Calculate signed distance fields for arbitrary meshes

Project description

Calculate signed distance fields for arbitrary meshes

This project calculates approximate SDFs for triangle meshes. It works for non-watertight meshes (meshes with holes), self-intersecting meshes, meshes with non-manifold geometry and meshes with inconsistently oriented faces.

Install

pip3 install mesh-to-sdf

Examples

Voxelize a mesh

The mesh_to_voxels function creates an N ✕ N ✕ N array of SDF values. In this example, a mesh reconstructed using Marching Cubes and then rendered.

from mesh_to_sdf import mesh_to_voxels

import trimesh
import skimage

mesh = trimesh.load('chair.obj')

voxels = mesh_to_voxels(mesh, 64, pad=True)

vertices, faces, normals, _ = skimage.measure.marching_cubes_lewiner(voxels, level=0)
mesh = trimesh.Trimesh(vertices=vertices, faces=faces, vertex_normals=normals)
mesh.show()

Example of a mesh and a reconstructed SDF voxel volume

Sample SDF points non-uniformly near the surface

This example creates 250,000 points, where most of the points are close to the surface and some are sampled uniformly. This is the method that is proposed and used in the DeepSDF paper. In this example, the resulting points are rendered in red where the SDF is positive and in blue where it is negative.

from mesh_to_sdf import sample_sdf_near_surface

import trimesh
import pyrender
import numpy as np

mesh = trimesh.load('chair.obj')

points, sdf = sample_sdf_near_surface(mesh, number_of_points=250000)

colors = np.zeros(points.shape)
colors[sdf < 0, 2] = 1
colors[sdf > 0, 0] = 1
cloud = pyrender.Mesh.from_points(points, colors=colors)
scene = pyrender.Scene()
scene.add(cloud)
viewer = pyrender.Viewer(scene, use_raymond_lighting=True, point_size=2)

Example of a mesh and a point cloud of non-uniformly sampled SDF points

How it works

The general pipeline for calculating SDF in this project is as follows:

  1. Create 100 virtual laser scans of the shape from multiple angles. These each consist of a normal buffer and a depth buffer.
  2. Use the inverse MVP matrix and depth buffer of each scan to calculate a world-space surface point cloud
  3. Determine the value of the SDF for each query point by finding the closest surface point using a kd-tree
  4. Determine the sign of the SDF using either the normal of the closest surface point or by checking it against the depth buffers of the scans. When using normals, the sign is determined with a dot product. When using the depth buffer method, the point is projected in the frame of each render. By comparing the depth element of the depth buffer and depth of the query point, we determine if the query point is seen by the camera. The sign of the point is positive if it is seen by any of the cameras.

This repository contains an implementation of the procedure proposed in the DeepSDF paper, as well as some alternatives.

Documentation

mesh_to_sdf

Calculate signed distance values for an array of given query points

mesh_to_sdf.mesh_to_sdf(mesh, query_points, surface_point_method='scan', sign_method='normal', bounding_radius=None, scan_count=100, scan_resolution=400, sample_point_count=10000000, normal_sample_count=11)

Parameters

  • mesh: a trimesh mesh
  • query_points: an N ✕ 3 numpy array, containing the points for which the signed distance function should be calculated.
  • See common parameters for the remaining parameters

Returns

  • a numpy array with N elemenents, containing the SDF for each query point

mesh_to_voxels

Calculate an N ✕ N ✕ N voxel volume of signed distance values for a given mesh. The mesh is first transformed to fit inside a cube ranging from -1 to 1.

mesh_to_sdf.mesh_to_voxels(mesh, voxel_resolution=64, surface_point_method='scan', sign_method='normal', scan_count=100, scan_resolution=400, sample_point_count=10000000, normal_sample_count=11, pad=False, check_result=False)

Parameters

  • mesh: a trimesh mesh
  • voxel_resolution: the resolution N of the resulting voxel volume
  • pad: if True, the resulting array is padded with ones, ensuring a mesh without holes when reconstructing with Marching Cubes
  • check_result: if True, the result is checked for continuity. If the voxel volume is not a plausible signed distance field, an exception is thrown.
  • See common parameters for the remaining parameters

Returns

  • a numpy array of shape N ✕ N ✕ N (or N + 2 ✕ N + 2 ✕ N + 2 when using padding)

sample_sdf_near_surface

Sample some points uniformly and some points near the shape surface and calculate SDFs for these points. This follows the procedure proposed in the DeepSDF paper. The mesh is first transformed to fit inside the unit sphere.

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

Parameters

  • mesh: a trimesh mesh
  • number_of_points: the number N of points to be sampled, including surface points and uniform points
  • min_size: The fraction of uniformly sampled that should be inside the shape. If this is 0.015 and less than 1.5% of uniformly sampled points have negative SDFs, an exception is thrown. This can be used to detect bad meshes.
  • See common parameters for the remaining parameters

Returns

  • points: an N ✕ 3 numpy array containing the sample points
  • sdf: a numpy array of size N with the corresponding SDF values

get_surface_point_cloud

Returns an intermediate data structure containing a surface point cloud, scans and a kd-tree of the point cloud. This can be used if SDFs will be calculated multiple times for the same mesh or for debugging.

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

Parameters

  • mesh: a trimesh mesh
  • See common parameters for the remaining parameters

Returns

  • an instance of SurfacePointCloud

Common parameters

  • surface_point_method: The method to generate a surface point cloud. Either 'scan' or 'sample'. The scanning method creates virtual scans while the sampling method uses the triangles to sample surface points. The sampling method only works with watertight meshes with correct face normals, but avoids some of the artifacts that the scanning method creates.

  • sign_method: The method to determine the signs of the SDF values. Either 'normal' or 'depth'. The normal method uses normals of the point cloud. It works better for meshes with holes, but sometimes results in "bubble" artifacts. The depth method avoids the bubble artifacts but is less accurate.

  • bounding_radius: The radius of a sphere that contains all mesh vertices. If None, this value is calculated using the mesh.

  • scan_count: Number of scans when using the scanning method

  • scan_resolution: Resolution for the scans in pixels.

  • sample_point_count: Number of points to sample when using surface_point_method='sample'

  • normal_sample_count: Number of nearby surface points to check when using sign_method='normal'. The sign of the resulting SDF is determined by majority vote.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mesh-to-sdf-0.0.6.tar.gz (11.2 kB view details)

Uploaded Source

Built Distribution

mesh_to_sdf-0.0.6-py3-none-any.whl (12.4 kB view details)

Uploaded Python 3

File details

Details for the file mesh-to-sdf-0.0.6.tar.gz.

File metadata

  • Download URL: mesh-to-sdf-0.0.6.tar.gz
  • Upload date:
  • Size: 11.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.5.0.1 requests/2.9.1 setuptools/45.0.0 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.5.2

File hashes

Hashes for mesh-to-sdf-0.0.6.tar.gz
Algorithm Hash digest
SHA256 e77d320cd85c2e9e95a62689ae7a75f389ce2aa9a80a0801459c8da5675cd3af
MD5 1d237aa2d6a52706e32b774292997ef9
BLAKE2b-256 5425afadf06a4638457caa76bf001f355b846e8bf1cad87a456996fb15cd7985

See more details on using hashes here.

Provenance

File details

Details for the file mesh_to_sdf-0.0.6-py3-none-any.whl.

File metadata

  • Download URL: mesh_to_sdf-0.0.6-py3-none-any.whl
  • Upload date:
  • Size: 12.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.5.0.1 requests/2.9.1 setuptools/45.0.0 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.5.2

File hashes

Hashes for mesh_to_sdf-0.0.6-py3-none-any.whl
Algorithm Hash digest
SHA256 3eea1e55b30452e41c5d7c8f0789d76ed81ef3fa5f17adf97e3512346cf90bd5
MD5 5f6635f264692cadacf6bf69b820b9be
BLAKE2b-256 54266da07575b6697f3ecb9fe53b37ffdc13a0726ca21156c58f44ef770c5a42

See more details on using hashes here.

Provenance

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page