Triangle mesh to signed-distance function (SDF)
Given a triangle mesh and a set of points, this library supports:
- Computing SDF of mesh at each point:
sdf(points) - Computing whether each point is inside mesh:
sdf.contains(points) - Computing nearest neighbor vertex index for each point:
sdf.nn(points)All operations are CPU-only and parallelized.
Quickstart
Install python binding: pip install mesdf
Prebuilt wheels are published for CPython 3.12-3.15 on Linux (x86_64, aarch64), macOS (x86_64, arm64) and Windows (x86_64).
Usage example:
from mesdf import SDF
# Load some mesh (don't necessarily need trimesh)
import trimesh
o = trimesh.load('some.obj')
f = SDF(o.vertices, o.faces); # (num_vertices, 3) and (num_faces, 3)
# Compute some SDF values (negative outside);
# takes a (num_points, 3) array, converts automatically
origin_sdf = f([0, 0, 0])
sdf_multi_point = f([[0, 0, 0],[1,1,1],[0.1,0.2,0.2]])
# Contains check
origin_contained = f.contains([0, 0, 0])
# Misc: nearest neighbor
origin_nn = f.nn([0, 0, 0])
# Misc: uniform surface point sampling
random_surface_points = f.sample_surface(10000)
# Misc: surface area
the_surface_area = f.surface_area
# All the functions also support an additional argument 'n_threads=<int>' to specify number of threads.
# by default we use min(32, n_cpus)
To modify the vertices/faces, you can change
f.vertices_mutable and f.faces_mutable, then call f.update() to
update the internal data structures.
You can also use
f.vertices and f.faces to access vertices and faces (non-writable).
Screenshots
Robustness under self-intersections:
Reasonable result for non-watertight mesh with multiple parts:
Reasonable result for voxel grid
C++ Library Usage
sdf::SDF sdf(verts, faces); // verts (n, 3) float, faces (m, 3) float
// SDF. points (k, 3) float; return (k) float
Eigen::Vector3f sdf_at_points = sdf(points);
// Containment test, equal (but maybe faster) than sdf >= 0.
// points (k, 3) float; return (k) bool
Eigen::Matrix<bool, -1, 1> contains_points = sdf.contains(points);
// Miscellaneous: nearest neighbor. points (k, 3) float; return (k) int
Eigen::VectorXi nn_verts_idxs = sdf.nn(points);
// Miscellaneous: uniformly random points on surface (generates 10000 in this case)
Eigen::Matrix<float, -1, 3> random_surface_points = sdf.sample_surface(10000);
// Surface area
float surface_area = sdf.surface_area
Note SDF is > 0 inside and < 0 outside mesh.
Use in a CMake project
The library is header-only (include/sdf/). Copy include/sdf into your project
and add its directories (plus Eigen) to your target's include path:
target_include_directories(your_target PRIVATE path/to/mesdf/include/sdf)
src/sdf.cpp and src/util.cpp must also be compiled into your target; see
CMakeLists.txt for the include paths the python extension uses.
Robust mode
By default 'robust' mode is used. sdf::SDF sdf(verts, faces, false) to disable.
The SDF computation will be slightly faster but may be incorrect if the mesh has self-intersections or incorrect winding (not CCW) on some faces.
Python
See the quickstart section for a usage example.
help(mesdf) will show more unimportant miscellaneous functions you may want to use (surface normal, area, etc.).
Copying
By default, SDF(verts, faces) will copy the vertices/faces to ensure memory safety,
especially since the arguments may be automatically converted.
Use SDF(verts, faces, copy=False) to prevent this, if you are sure verts/faces are
of types np.float32/np.uint32 respectively and will not be destroyed before the SDF instance.
In this mode, vertices_mutable/faces_mutable are unavailable.
Warning about reliability
In robust mode (default) we use raytracing (parity count) to check containment. Currently the ray tracing has the same limitation as embree, that is when ray exactly hits an edge the intersection gets double counted, inverting the sign of the distance function. This is theoretically unlikely for random points but can occur either due to floating point error or if points and mesh vertices are both taken from a grid. In practice, we (1) randomize the ray tracing direction and (2) trace 3 rays along different axes and take majority to decrease the likelihood of this occurring.
In non-robust mode we use nearest surface normal to check containment. The contains check (and SDF sign) will be wrong under self-intersection or if normals are incorrectly oriented.
Dependencies
- Eigen 3 (provided by the
eigencypython package at build time) - Vendored (no installation needed):
- nanoflann
- nushoin/RTree
Build + Install
pip install . (or pip install -e .) builds the extension with
scikit-build-core; only a C++17
compiler is required, CMake/Ninja/pybind11/Eigen come in as build dependencies.
Wheels for all supported platforms and Python versions are built in CI by
.github/workflows/build_wheels.yml and published to PyPI on pushes to main.
Tests
pip install -e '.[test]' && pytest tests/test.py
Benchmark
vs. trimesh
All benchmarks are ran on a 6-core CPU (Intel i7 8th generation, high-performance laptop). More is better.
| Model vertices | trimesh contains eval/s (numpy) | trimesh contains eval/s (pyembree) | our SDF evals / s (robust) | our SDF evals / s (non-robust) |
|---|---|---|---|---|
| 3241 | 29,555 | 237,855 | 5,077,725 | 8,187,117 |
| 49246 | 6,835 | 62,058 | 2,971,137 | 4,407,045 |
| 179282 | 1,301 | 20,157 | 1,672,859 | 1,987,869 |
vs. JianWenPL/multiperson (CUDA)
Here we compare to https://github.com/JiangWenPL/multiperson/tree/master/sdf. The GPU code is ran on a single GTX 1080 Ti, and CPU is a 6-core i7 5820K. I evaluate the SDF on an x-by-x-by-x grid in [-1,1]^3.
Results for SMPL model (13776 faces, 6890 vertices)
| Grid resolution | multiperson SDF runtime, ms | our runtime, ms (robust) | our runtime, ms (non-robust) | speedup (robust) |
|---|---|---|---|---|
| 32 | 46.70460891723633 | 13.006210327148438 | 7.317066192626953 | 3.59 |
| 64 | 236.6414031982422 | 62.57128715515137 | 51.19466781616211 | 3.78 |
| 128 | 1521.0322265625 | 400.36678314208984 | 347.3823070526123 | 3.80 |
Results for SMPL-X model (20908 faces, 10475 vertices).
| Grid resolution | multiperson SDF runtime, ms | our runtime, ms (robust) | our runtime, ms (non-robust) | speedup (robust) |
|---|---|---|---|---|
| 32 | 71.34893035888672 | 13.09061050415039 | 8.291006088256836 | 5.45 |
| 64 | 353.7056579589844 | 66.21336936950684 | 57.36279487609863 | 5.34 |
| 128 | 2303.649658203125 | 477.12063789367676 | 396.78120613098145 | 4.83 |
Notes:
- This is not really a fair comparison, since the SDF computed in multiperson is more exact (computes distance to all faces) and mine is approximate (only distance to faces adjacent to nearest neighbors). Both methods are prone to numerical error but perhaps mine is more so.
- Basically the more faces the mesh has, the more performance advantage our method has. For small meshes with very few faces the CUDA implementation should be somewhat faster.
- My implementation is designed to evaluate on arbitrary continuous points, so it requires the meshgrid points to be generated and passed, while the implementation in multiperson assumes a grid which it generates on the fly, potentially saving some memory access time especially when resolution is high.
License
BSD 2-clause
This library relies on the Eigen (MPL2) nanoflann (BSD) and RTree (MIT) libraries.
Metadata
Release files for mesdf 0.1.13
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
Total release size: 3.5 MB
Release files / mesdf-0.1.13-cp315-cp315-win_amd64.whl
| Download URL | mesdf-0.1.13-cp315-cp315-win_amd64.whl |
|---|---|
| Size | 342.0 kB |
| Tags | CPython 3.15 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
5e1dccfd782af8722b534d5cfd4f81d247c35ae469be19468e4eec627c00aed1
|
|
BLAKE2b-256 checksum How to use checksums |
8c76a4082cf88824fcd6b1ecf8a6a93db1516dd8acac077ab1f1ff764f83a884
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | mesdf-0.1.13-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 154.6 kB |
| Tags | CPython 3.15 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
a3066e6b79f30a86376c426b7ff0a8b03f760a408808550f8502f744f23e1657
|
|
BLAKE2b-256 checksum How to use checksums |
d1b3e1dab8b1fa3b657b5f405d43c01d8488ed30a02a9984f46ed03d8a1c2eec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
| Download URL | mesdf-0.1.13-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 139.5 kB |
| Tags | CPython 3.15 Linux glibc 2.27+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
e2ad9f00a2372bb62f0e03c511346c0d371acfdbd9025b97859623a721920dc3
|
|
BLAKE2b-256 checksum How to use checksums |
7571cf78e8a60a9439e5dd9d42c70154fc6873fb5ef903c56f2a422e79eee7f0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp315-cp315-macosx_11_0_arm64.whl
| Download URL | mesdf-0.1.13-cp315-cp315-macosx_11_0_arm64.whl |
|---|---|
| Size | 120.0 kB |
| Tags | CPython 3.15 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
c20bfa3e77c5a8a7419e51ab014f857b2352020d3c21336335631acb97bee583
|
|
BLAKE2b-256 checksum How to use checksums |
38bcb4f55608f6685568fe4cf9adde0aec0eef31a8d4e0a643d3a76579acbb35
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp315-cp315-macosx_10_15_x86_64.whl
| Download URL | mesdf-0.1.13-cp315-cp315-macosx_10_15_x86_64.whl |
|---|---|
| Size | 130.9 kB |
| Tags | CPython 3.15 macOS 10.15+ x86-64 |
|
SHA-256 checksum How to use checksums |
86085d0f21d05e56c3d5af7dd94fc1c4d3811dffa0c3206eec6e75fdd053ac2b
|
|
BLAKE2b-256 checksum How to use checksums |
c895049103791018d5b4962effe595e6c239d44ed727e936be61e6878eff33bc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp314-cp314-win_amd64.whl
| Download URL | mesdf-0.1.13-cp314-cp314-win_amd64.whl |
|---|---|
| Size | 341.9 kB |
| Tags | CPython 3.14 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
792b7f04e1013ba23d1948f02b221ac8a816678b4291505751c85faf9d5070be
|
|
BLAKE2b-256 checksum How to use checksums |
21153d66c5556e403d879d3d50855bb9d95f88242e71dd5f1be24a2c067fc230
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | mesdf-0.1.13-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 154.6 kB |
| Tags | CPython 3.14 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
28e9cb13e587cec2a014683cbc12292cdea94001a7b149a26c95eb8af2ab0074
|
|
BLAKE2b-256 checksum How to use checksums |
86a4ca747e76f336d67a00ea244442fa95724482b9c11275c85a6fbee26473a8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
| Download URL | mesdf-0.1.13-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 139.5 kB |
| Tags | CPython 3.14 Linux glibc 2.27+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
93ef53b68d39336627d43568282b8132ccb1512ac182ef6c6215a9d6d5f5326a
|
|
BLAKE2b-256 checksum How to use checksums |
0d074242ca300e4380cd95c960132164d6edd37da54f4043b274a927039cec9b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp314-cp314-macosx_11_0_arm64.whl
| Download URL | mesdf-0.1.13-cp314-cp314-macosx_11_0_arm64.whl |
|---|---|
| Size | 120.0 kB |
| Tags | CPython 3.14 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
39bfd5c74868049250b52f3287b38e0fdafe4cfce3b73dc291c13e57fe96f5e9
|
|
BLAKE2b-256 checksum How to use checksums |
33f379322e7261d532ec0d152d7cd1dab6bf9fdac02a1306602ee4e7e334f6f5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp314-cp314-macosx_10_15_x86_64.whl
| Download URL | mesdf-0.1.13-cp314-cp314-macosx_10_15_x86_64.whl |
|---|---|
| Size | 130.9 kB |
| Tags | CPython 3.14 macOS 10.15+ x86-64 |
|
SHA-256 checksum How to use checksums |
2b7b658d1994c45e73033631d8e0ba46feafe042d9f36c931e3047fb8a5e7da8
|
|
BLAKE2b-256 checksum How to use checksums |
de76bff793bf38bcba0648d6a7c0983d592d190973b1dd2a86132dc6aad2a808
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp313-cp313-win_amd64.whl
| Download URL | mesdf-0.1.13-cp313-cp313-win_amd64.whl |
|---|---|
| Size | 331.4 kB |
| Tags | CPython 3.13 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
9d5bfe36b42b3b36ec45150792ebb05799040cd31d1feff6613269c8a902caf3
|
|
BLAKE2b-256 checksum How to use checksums |
610f96c8e527fd4b442e78a55151d23fb5e5d5c3f72745a8c6db2e755233d683
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | mesdf-0.1.13-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 154.3 kB |
| Tags | CPython 3.13 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
430ed4ded577b7e122aec6917c7a45361d6c825099d8380177bf1639886fc03e
|
|
BLAKE2b-256 checksum How to use checksums |
56b6885aec4bb06d45543f88f6a7fad64bfc20cdcb360862b766ed1605f80861
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
| Download URL | mesdf-0.1.13-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 139.1 kB |
| Tags | CPython 3.13 Linux glibc 2.27+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
46e0f9431ab488174d4d9e08c6e8c5da87cc39ebacb93e2d4f2b822363321f17
|
|
BLAKE2b-256 checksum How to use checksums |
63e3cae08bd3a6b23e8992be2ad40f1b2f55d89063fa8aec5ff231a297bce9e9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp313-cp313-macosx_11_0_arm64.whl
| Download URL | mesdf-0.1.13-cp313-cp313-macosx_11_0_arm64.whl |
|---|---|
| Size | 119.8 kB |
| Tags | CPython 3.13 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
61c68de223be7b318f805e4b38544d633b18e88ff56b9f344b73a1a05fa09978
|
|
BLAKE2b-256 checksum How to use checksums |
8f7bd432477b00c26b9e71787ce76762ae67fe699cebdf56b1dd5d359c760e45
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp313-cp313-macosx_10_13_x86_64.whl
| Download URL | mesdf-0.1.13-cp313-cp313-macosx_10_13_x86_64.whl |
|---|---|
| Size | 130.6 kB |
| Tags | CPython 3.13 macOS 10.13+ x86-64 |
|
SHA-256 checksum How to use checksums |
344f14460ebbbd2f69e45bacbd5b8c00cb843d2b0040abc8fb2f88811a0edcd8
|
|
BLAKE2b-256 checksum How to use checksums |
b15f659440667df05c1edd79a96c2a7dc056a626497ab81d1729f305a6072b15
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp312-cp312-win_amd64.whl
| Download URL | mesdf-0.1.13-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 331.3 kB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
233d043d1a56c6c53a65469ad1f6502fde0a1c615633068f901096738fa79350
|
|
BLAKE2b-256 checksum How to use checksums |
97f25d4a3192bf5927cdb8cf207e1952a770c82bb80b6b559e13f2a631926b23
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | mesdf-0.1.13-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 154.3 kB |
| Tags | CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
dbf5859820914069b9c6c17cbbfb50376172d6ce55e262249451f94cdcee4567
|
|
BLAKE2b-256 checksum How to use checksums |
e1a2941a827f9a491a3fa3b99a77645edd707ba430fa0af88072bb770cd22300
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
| Download URL | mesdf-0.1.13-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 139.1 kB |
| Tags | CPython 3.12 Linux glibc 2.27+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
5f0887f8d0b54e745d8ae43eebb4de672ee9a03d91138806941c474f4bc55d55
|
|
BLAKE2b-256 checksum How to use checksums |
c462f41b887bf71b20845e9bb6b442ef50bd7f2caf1e68a07813a89eb6ba9679
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp312-cp312-macosx_11_0_arm64.whl
| Download URL | mesdf-0.1.13-cp312-cp312-macosx_11_0_arm64.whl |
|---|---|
| Size | 119.8 kB |
| Tags | CPython 3.12 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
1590c681ce060f7e03c6e82e85df474e596a9e16f758fc351e3d52464c8686f6
|
|
BLAKE2b-256 checksum How to use checksums |
0bfd4c962e04b602474dc1b427d1ce4a9c03b4f1702ce597527cd891596b5332
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Release files / mesdf-0.1.13-cp312-cp312-macosx_10_13_x86_64.whl
| Download URL | mesdf-0.1.13-cp312-cp312-macosx_10_13_x86_64.whl |
|---|---|
| Size | 130.6 kB |
| Tags | CPython 3.12 macOS 10.13+ x86-64 |
|
SHA-256 checksum How to use checksums |
9a01fb84b2c82c721dd99e986d871b57ee5969905488484c7ee0a3512ca1ce2e
|
|
BLAKE2b-256 checksum How to use checksums |
ba58ff392e8035ae01037a4b02379c2736144086fb9b81e0ca5add7825d7354c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.15.1
|
Security for mesdf 0.1.13
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.