pysdf-easy 0.1.10__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ Copyright Alex Yu 2020
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice,
7
+ this list of conditions and the following disclaimer.
8
+
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
17
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
23
+ POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,12 @@
1
+ include README.md
2
+ include LICENSE.txt
3
+ include MANIFEST.in
4
+ include setup.py
5
+ include pybind.cpp
6
+ include src/sdf.cpp
7
+ include src/renderer.cpp
8
+ include src/util.cpp
9
+ include include/sdf/sdf.hpp
10
+ include include/sdf/internal/sdf_util.hpp
11
+ include include/sdf/internal/nanoflann.hpp
12
+ include include/sdf/internal/RTree.h
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.4
2
+ Name: pysdf-easy
3
+ Version: 0.1.10
4
+ Summary: SDF: Convert triangle mesh to continuous signed distance function + some other mesh utilities
5
+ Home-page: https://github.com/sxyu/sdf
6
+ Author: Alex Yu
7
+ Author-email: alexyu99126@gmail.com
8
+ License-File: LICENSE.txt
9
+ Dynamic: author
10
+ Dynamic: author-email
11
+ Dynamic: description
12
+ Dynamic: home-page
13
+ Dynamic: license-file
14
+ Dynamic: summary
15
+
16
+ Convert triangle mesh to SDF https://github.com/sxyu/sdf. Also includes uniform surface sampling and a ray-casting based software renderer.
@@ -0,0 +1,182 @@
1
+ # Triangle mesh to signed-distance function (SDF)
2
+
3
+ > ⚠️ **Note from maintainer**: This repository is a fork of the excellent [sxyu/sdf](https://github.com/sxyu/sdf). It was created specifically to resolve widespread `pip install` compilation errors on modern Windows/MSVC setups (such as `pybind11 requires MSVC 2017 or newer` and `C2039: "high_resolution_clock": is not a member of "std::chrono"`). If you just want to install the package without C++ compilation headaches, use the pre-built binaries from this fork:
4
+ > `pip install pysdf-easy`
5
+
6
+ Given a triangle mesh and a set of points, this library supports:
7
+ 1. Computing SDF of mesh at each point: `sdf(points)`
8
+ 2. Computing whether each point is inside mesh: `sdf.contains(points)`
9
+ 3. Computing nearest neighbor vertex index for each point: `sdf.nn(points)`
10
+ All operations are CPU-only and parallelized.
11
+
12
+ ## Quickstart
13
+
14
+ **Install python binding**: `pip install pysdf-easy`
15
+
16
+ *(The original package is named `pysdf`, but this maintained fork with pre-compiled compatibility wheels is available under `pysdf-easy`. **Note: The import statement remains exactly the same as the original library.**)*
17
+
18
+ ### Usage example:
19
+ ```python
20
+ from pysdf import SDF
21
+
22
+ # Load some mesh (don't necessarily need trimesh)
23
+ import trimesh
24
+ o = trimesh.load('some.obj')
25
+ f = SDF(o.vertices, o.faces); # (num_vertices, 3) and (num_faces, 3)
26
+
27
+ # Compute some SDF values (negative outside);
28
+ # takes a (num_points, 3) array, converts automatically
29
+ origin_sdf = f([0, 0, 0])
30
+ sdf_multi_point = f([[0, 0, 0],[1,1,1],[0.1,0.2,0.2]])
31
+
32
+ # Contains check
33
+ origin_contained = f.contains([0, 0, 0])
34
+
35
+ # Misc: nearest neighbor
36
+ origin_nn = f.nn([0, 0, 0])
37
+
38
+ # Misc: uniform surface point sampling
39
+ random_surface_points = f.sample_surface(10000)
40
+
41
+ # Misc: surface area
42
+ the_surface_area = f.surface_area
43
+
44
+ # All the functions also support an additional argument 'n_threads=<int>' to specify number of threads.
45
+ # by default we use min(32, n_cpus)
46
+ ```
47
+ To modify the vertices/faces, you can change
48
+ `f.vertices_mutable` and `f.faces_mutable`, then call `f.update()` to
49
+ update the internal data structures.
50
+ You can also use
51
+ `f.vertices` and `f.faces` to access vertices and faces (non-writable).
52
+
53
+ ## Screenshots
54
+
55
+ <img src="https://github.com/sxyu/sdf/blob/master/readme-img/human.gif"
56
+ width="400">
57
+
58
+ Robustness under self-intersections:
59
+
60
+ <img src="https://github.com/sxyu/sdf/blob/master/readme-img/smpl.png"
61
+ width="400">
62
+
63
+ Reasonable result for non-watertight mesh with multiple parts:
64
+
65
+ <img src="https://github.com/sxyu/sdf/blob/master/readme-img/teapot.gif"
66
+ width="400">
67
+
68
+ Reasonable result for voxel grid
69
+
70
+ <img src="https://github.com/sxyu/sdf/blob/master/readme-img/voxel.png"
71
+ width="400">
72
+
73
+ ## C++ Library Usage
74
+ ```cpp
75
+ sdf::SDF sdf(verts, faces); // verts (n, 3) float, faces (m, 3) float
76
+
77
+ // SDF. points (k, 3) float; return (k) float
78
+ Eigen::Vector3f sdf_at_points = sdf(points);
79
+
80
+ // Containment test, equal (but maybe faster) than sdf >= 0.
81
+ // points (k, 3) float; return (k) bool
82
+ Eigen::Matrix<bool, -1, 1> contains_points = sdf.contains(points);
83
+
84
+ // Miscellaneous: nearest neighbor. points (k, 3) float; return (k) int
85
+ Eigen::VectorXi nn_verts_idxs = sdf.nn(points);
86
+
87
+ // Miscellaneous: uniformly random points on surface (generates 10000 in this case)
88
+ Eigen::Matrix<float, -1, 3> random_surface_points = sdf.sample_surface(10000);
89
+
90
+ // Surface area
91
+ float surface_area = sdf.surface_area
92
+ ```
93
+ Note SDF is > 0 inside and < 0 outside mesh.
94
+
95
+ ## Use in CMake project
96
+ - `find_package(sdf)`
97
+ - After defining a target: `target_link_libraries(your_target sdf::sdf)`
98
+
99
+ ### Robust mode
100
+ By default 'robust' mode is used. `sdf::SDF sdf(verts, faces, false)` to disable.
101
+ 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.
102
+
103
+ ## Python
104
+ See the quickstart section for a usage example.
105
+ `help(pysdf)` will show more unimportant miscellaneous functions you may want to use (surface normal, area, etc.).
106
+
107
+ ### Copying
108
+ By default, `SDF(verts, faces)` will copy the vertices/faces to ensure memory safety,
109
+ especially since the arguments may be automatically converted.
110
+ Use `SDF(verts, faces, copy=False)` to prevent this, if you are sure verts/faces are
111
+ of types np.float32/np.uint32 respectively and will not be destroyed before the SDF instance.
112
+ In this mode, `vertices_mutable`/`faces_mutable` are unavailable.
113
+
114
+ ## Warning about reliability
115
+ In robust mode (default) we use raytracing (parity count) to check containment.
116
+ Currently the ray tracing has the same limitation as embree,
117
+ that is when ray exactly hits an edge the intersection gets double counted, inverting the sign
118
+ of the distance function.
119
+ 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.
120
+ 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.
121
+
122
+ In non-robust mode we use nearest surface normal to check containment.
123
+ The contains check (and SDF sign) will be wrong under self-intersection or if normals are incorrectly oriented.
124
+
125
+ ## Dependencies
126
+ - Eigen 3 (Python: automatically downloaded if needed)
127
+ - Vendored (no installation needed):
128
+ - nanoflann
129
+ - nushoin/RTree
130
+ - Optional:
131
+ - meshview https://github.com/sxyu/meshview for demo
132
+
133
+ ## Build + Install
134
+ `mkdir build && cd build && cmake .. && make -j4 && sudo make install`
135
+
136
+ ## Demo
137
+ A demo program can optionally be built, if meshview is installed.
138
+ To use it, run `./sdf-demo BASIC_OBJ_FILE`. Try the `sample-obj/*.obj` included in the project.
139
+
140
+ ## Benchmark
141
+
142
+ ### vs. trimesh
143
+
144
+ All benchmarks are ran on a 6-core CPU (Intel i7 8th generation, high-performance laptop).
145
+ More is better.
146
+
147
+ | Model vertices | trimesh contains eval/s (numpy) | trimesh contains eval/s (pyembree) | our SDF evals / s (robust) | our SDF evals / s (non-robust) |
148
+ | ------------- | ------------- | ------------- | ------------- | ------------- |
149
+ | 3241 | 29,555| 237,855 | 5,077,725 | 8,187,117 |
150
+ | 49246 | 6,835 | 62,058 | 2,971,137 | 4,407,045 |
151
+ | 179282 | 1,301 | 20,157 | 1,672,859 | 1,987,869 |
152
+
153
+ ### vs. JianWenPL/multiperson (CUDA)
154
+
155
+ Here we compare to https://github.com/JiangWenPL/multiperson/tree/master/sdf.
156
+ 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.
157
+
158
+ Results for SMPL model (13776 faces, 6890 vertices)
159
+
160
+ | Grid resolution | multiperson SDF runtime, ms | our runtime, ms (robust) | our runtime, ms (non-robust) | speedup (robust) |
161
+ | ------------ | ------------ | ------------ | ------------ | ------------ |
162
+ | 32 | 46.70460891723633 | 13.006210327148438 | 7.317066192626953 | 3.59 |
163
+ | 64 | 236.6414031982422 | 62.57128715515137 | 51.19466781616211 | 3.78 |
164
+ | 128 | 1521.0322265625 | 400.36678314208984 | 347.3823070526123 | 3.80 |
165
+
166
+ Results for SMPL-X model (20908 faces, 10475 vertices).
167
+
168
+ | Grid resolution | multiperson SDF runtime, ms | our runtime, ms (robust) | our runtime, ms (non-robust) | speedup (robust) |
169
+ | ------------ | ------------ | ------------ | ------------ | ------------ |
170
+ | 32 | 71.34893035888672 | 13.09061050415039 | 8.291006088256836 | 5.45 |
171
+ | 64 | 353.7056579589844 | 66.21336936950684 | 57.36279487609863 | 5.34 |
172
+ | 128 | 2303.649658203125 | 477.12063789367676 | 396.78120613098145 | 4.83 |
173
+
174
+ Notes:
175
+ - 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.
176
+ - 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.
177
+ - 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.
178
+
179
+ ## License
180
+ BSD 2-clause
181
+
182
+ This library relies on the Eigen (MPL2) nanoflann (BSD) and RTree (MIT) libraries.