|
1 | 1 | #  |
2 | 2 | Surface reconstruction for particle data from SPH simulations, written in Rust. |
3 | 3 |
|
4 | | -This is a basic but high-performance implementation of surface reconstruction for SPH using marching cubes. |
| 4 | +## Introduction |
| 5 | + |
| 6 | +This is a basic but high-performance implementation of a marching cubes based surface reconstruction for SPH fluid simulations (e.g performed with [SPlisHSPlasH](https://github.com/InteractiveComputerGraphics/SPlisHSPlasH)). |
5 | 7 | The output of this tool is the reconstructed triangle surface mesh of the fluid. |
6 | 8 | At the moment it does not compute normals or other additional data. |
7 | | -As input, it supports particle positions from .vtk files and binary .xyz files. In addition, required parameters are the kernel radius and particle radius (to compute the volume of particles) used for the original SPH simulation as well as the surface threshold. |
| 9 | +As input, it supports particle positions from .vtk files and binary .xyz files (i.e. files containing a binary dump of a particle position array). In addition, required parameters are the kernel radius and particle radius (to compute the volume of particles) used for the original SPH simulation as well as the surface threshold. |
| 10 | + |
| 11 | +The implementation first computes the density of each particle using the typical SPH approach with a cubic kernel. |
| 12 | +This density is then evaluated or mapped onto a sparse grid using spatial hashing in the support radius of each particle. |
| 13 | +This implies that memory is only allocated in areas where the fluid density is non-zero. This is in contrast to a naive approach where the marching cubes background grid is allocated for the whole domain. |
| 14 | +Finally, the marching cubes reconstruction is performed only in those grid cells where the density values cross the surface threshold. Cells completely in the interior of the fluid are skipped. |
| 15 | + |
| 16 | +Due the use of hash maps and multi-threading (if enabled), the output of this implementation is not deterministic. |
| 17 | +In the future, flags may be added to switch the internally data structures to use binary trees for debugging. |
8 | 18 |
|
9 | | -The implementation first computes the density of each particles using the typical SPH approach with a cubic kernel. This density is then interpolated onto a sparse grid using spatial hashing in the support radius of each particle. Finally, the marching cubes reconstruction is performed only in those grid cells where the density values cross the surface threshold. |
| 19 | +As shown below, the tool can handle the output of large simulations. |
| 20 | +However, it was not tested with a wide range of parameters and may not be totally robust against corner-cases or extreme parameters. |
| 21 | +If you experience problems, please report them together with your input data. |
10 | 22 |
|
11 | | -Due the use of hash maps in release mode and multi-threading (if enabled), the output of this implementation is not deterministic. |
12 | | -To help with debugging, the implementation switches to binary trees in debug builds. |
| 23 | +## Installation |
| 24 | + |
| 25 | +The command-line tool can be built from this repository but is also available on crates.io. |
| 26 | +If you have a [Rust toolchain installed](https://www.rust-lang.org/tools/install) you can install `splashsurf` with the command |
| 27 | +``` |
| 28 | +cargo install splashsurf |
| 29 | +``` |
13 | 30 |
|
14 | 31 | ## Usage |
15 | 32 |
|
@@ -64,44 +81,44 @@ For example: |
64 | 81 | ``` |
65 | 82 | splashsurf "/home/user/canyon.xyz" --output-dir="/home/user/temp" --particle-radius=0.011 --kernel-radius=4.0 --cube-size=1.5 --surface-threshold=0.6 --mt-particles |
66 | 83 | ``` |
67 | | -With these parameters, a scene with 13353401 particles is reconstructed in less than 26.5s on a i7 8700K: |
| 84 | +With these parameters, a scene with 13353401 particles is reconstructed in nearly than 25s on a i9 9900K. The output is a mesh with 6016212 triangles. |
68 | 85 | ``` |
69 | | -[2020-05-12T20:22:28.441899+02:00][splashsurf::reconstruction][INFO] Loading dataset from "/home/user/canyon.xyz"... |
70 | | -[2020-05-12T20:22:28.582334+02:00][splashsurf::reconstruction][INFO] Loaded dataset with 13353401 particle positions. |
71 | | -[2020-05-12T20:22:28.628091+02:00][splashsurf_lib][INFO] Minimal enclosing bounding box of particles was computed as: AxisAlignedBoundingBox { min: [-25.0060978, -5.0146289, -40.0634613], max: [24.4994926, 18.3062096, 39.7757950] } |
72 | | -[2020-05-12T20:22:28.628109+02:00][splashsurf_lib][INFO] Using a grid with 6002x2828x9679 points and 6001x2827x9678 cells of edge length 0.0165. |
73 | | -[2020-05-12T20:22:28.628112+02:00][splashsurf_lib][INFO] The resulting domain size is: AxisAlignedBoundingBox { min: [-49.7588959, -16.6750488, -79.9830933], max: [49.2576065, 29.9704514, 79.7039032] } |
74 | | -[2020-05-12T20:22:28.628115+02:00][splashsurf_lib][INFO] Starting neighborhood search... |
75 | | -[2020-05-12T20:22:30.943285+02:00][splashsurf_lib][INFO] Computing particle densities... |
76 | | -[2020-05-12T20:22:31.967240+02:00][splashsurf_lib::density_map][INFO] Starting construction of sparse density map for 13353401 particles... |
77 | | -[2020-05-12T20:22:31.986757+02:00][splashsurf_lib::density_map][INFO] To take into account the kernel evaluation radius, the allowed domain of particles was restricted to: AxisAlignedBoundingBox { min: [-49.7093468, -16.6254997, -79.9335403], max: [49.2080574, 29.9209023, 79.6543503] } |
78 | | -[2020-05-12T20:22:50.536691+02:00][splashsurf_lib::density_map][INFO] Sparse density map with 31519986 point data values was constructed. |
79 | | -[2020-05-12T20:22:50.536710+02:00][splashsurf_lib::density_map][INFO] Construction of sparse density map done. |
80 | | -[2020-05-12T20:22:50.556266+02:00][splashsurf_lib::marching_cubes][INFO] Starting interpolation of cell data for marching cubes... |
81 | | -[2020-05-12T20:22:54.175469+02:00][splashsurf_lib::marching_cubes][INFO] Generated cell data for marching cubes with 3009863 cells and 3011516 vertices. |
82 | | -[2020-05-12T20:22:54.175481+02:00][splashsurf_lib::marching_cubes][INFO] Interpolation done. |
83 | | -[2020-05-12T20:22:54.175484+02:00][splashsurf_lib::marching_cubes][INFO] Starting marching cubes triangulation of 3009863 cells... |
84 | | -[2020-05-12T20:22:54.329789+02:00][splashsurf_lib::marching_cubes][INFO] Generated surface mesh with 6016212 triangles and 3011516 vertices. |
85 | | -[2020-05-12T20:22:54.329799+02:00][splashsurf_lib::marching_cubes][INFO] Triangulation done. |
86 | | -[2020-05-12T20:22:54.345902+02:00][splashsurf::reconstruction][INFO] Writing surface mesh to "/home/user/temp/canyon_surface.xyz"... |
87 | | -[2020-05-12T20:22:54.674636+02:00][splashsurf::reconstruction][INFO] Done. |
88 | | -[2020-05-12T20:22:54.710916+02:00][splashsurf][INFO] Finished processing all inputs. |
89 | | -[2020-05-12T20:22:54.710934+02:00][splashsurf][INFO] surface reconstruction cli: 100.00%, 26269.02ms/call @ 0.04Hz |
90 | | -[2020-05-12T20:22:54.710936+02:00][splashsurf][INFO] loading particle positions: 0.53%, 140.43ms/call @ 0.04Hz |
91 | | -[2020-05-12T20:22:54.710938+02:00][splashsurf][INFO] reconstruct_surface: 98.08%, 25763.55ms/call @ 0.04Hz |
92 | | -[2020-05-12T20:22:54.710939+02:00][splashsurf][INFO] compute minimum enclosing aabb: 0.18%, 45.76ms/call @ 0.04Hz |
93 | | -[2020-05-12T20:22:54.710941+02:00][splashsurf][INFO] neighborhood_search: 8.99%, 2315.17ms/call @ 0.04Hz |
94 | | -[2020-05-12T20:22:54.710942+02:00][splashsurf][INFO] parallel_generate_cell_to_particle_map: 15.43%, 357.13ms/call @ 0.04Hz |
95 | | -[2020-05-12T20:22:54.710944+02:00][splashsurf][INFO] get_cell_neighborhoods_par: 2.62%, 60.63ms/call @ 0.04Hz |
96 | | -[2020-05-12T20:22:54.710945+02:00][splashsurf][INFO] calculate_particle_neighbors_par: 57.23%, 1325.03ms/call @ 0.04Hz |
97 | | -[2020-05-12T20:22:54.710947+02:00][splashsurf][INFO] parallel_compute_particle_densities: 1.20%, 308.73ms/call @ 0.04Hz |
98 | | -[2020-05-12T20:22:54.710948+02:00][splashsurf][INFO] parallel_generate_sparse_density_map: 72.15%, 18589.03ms/call @ 0.04Hz |
99 | | -[2020-05-12T20:22:54.710949+02:00][splashsurf][INFO] triangulate_density_map: 14.71%, 3789.63ms/call @ 0.04Hz |
100 | | -[2020-05-12T20:22:54.710951+02:00][splashsurf][INFO] interpolate_points_to_cell_data: 95.50%, 3619.22ms/call @ 0.04Hz |
101 | | -[2020-05-12T20:22:54.710952+02:00][splashsurf][INFO] generate_iso_surface_vertices: 68.66%, 2484.79ms/call @ 0.04Hz |
102 | | -[2020-05-12T20:22:54.710953+02:00][splashsurf][INFO] relative_to_threshold_postprocessing: 31.34%, 1134.40ms/call @ 0.04Hz |
103 | | -[2020-05-12T20:22:54.710955+02:00][splashsurf][INFO] triangulate: 4.50%, 170.41ms/call @ 0.04Hz |
104 | | -[2020-05-12T20:22:54.710956+02:00][splashsurf][INFO] write surface mesh to file: 1.25%, 328.75ms/call @ 0.04Hz |
| 86 | +[2020-08-25T15:52:34.515885+02:00][splashsurf::reconstruction][INFO] Loading dataset from "/local/data/temp/canyon.xyz"... |
| 87 | +[2020-08-25T15:52:34.655354+02:00][splashsurf::reconstruction][INFO] Loaded dataset with 13353401 particle positions. |
| 88 | +[2020-08-25T15:52:34.684734+02:00][splashsurf_lib][INFO] Minimal enclosing bounding box of particles was computed as: AxisAlignedBoundingBox { min: [-25.0060978, -5.0146289, -40.0634613], max: [24.4994926, 18.3062096, 39.7757950] } |
| 89 | +[2020-08-25T15:52:34.684748+02:00][splashsurf_lib][INFO] Using a grid with 6002x2828x9679 points and 6001x2827x9678 cells of edge length 0.0165. |
| 90 | +[2020-08-25T15:52:34.684753+02:00][splashsurf_lib][INFO] The resulting domain size is: AxisAlignedBoundingBox { min: [-49.7588959, -16.6750488, -79.9830933], max: [49.2576065, 29.9704514, 79.7039032] } |
| 91 | +[2020-08-25T15:52:34.684756+02:00][splashsurf_lib][INFO] Starting neighborhood search... |
| 92 | +[2020-08-25T15:52:36.570860+02:00][splashsurf_lib][INFO] Computing particle densities... |
| 93 | +[2020-08-25T15:52:37.645919+02:00][splashsurf_lib::density_map][INFO] Starting construction of sparse density map for 13353401 particles... |
| 94 | +[2020-08-25T15:52:37.653068+02:00][splashsurf_lib::density_map][INFO] To take into account the kernel evaluation radius, the allowed domain of particles was restricted to: AxisAlignedBoundingBox { min: [-49.7093468, -16.6254997, -79.9335403], max: [49.2080574, 29.9209023, 79.6543503] } |
| 95 | +[2020-08-25T15:52:55.559939+02:00][splashsurf_lib::density_map][INFO] Sparse density map with 31519986 point data values was constructed. |
| 96 | +[2020-08-25T15:52:55.559999+02:00][splashsurf_lib::density_map][INFO] Construction of sparse density map done. |
| 97 | +[2020-08-25T15:52:55.560005+02:00][splashsurf_lib::marching_cubes][INFO] Starting interpolation of cell data for marching cubes... |
| 98 | +[2020-08-25T15:52:59.118442+02:00][splashsurf_lib::marching_cubes][INFO] Generated cell data for marching cubes with 3009863 cells and 3011516 vertices. |
| 99 | +[2020-08-25T15:52:59.118470+02:00][splashsurf_lib::marching_cubes][INFO] Interpolation done. |
| 100 | +[2020-08-25T15:52:59.118474+02:00][splashsurf_lib::marching_cubes][INFO] Starting marching cubes triangulation of 3009863 cells... |
| 101 | +[2020-08-25T15:52:59.279570+02:00][splashsurf_lib::marching_cubes][INFO] Generated surface mesh with 6016212 triangles and 3011516 vertices. |
| 102 | +[2020-08-25T15:52:59.279597+02:00][splashsurf_lib::marching_cubes][INFO] Triangulation done. |
| 103 | +[2020-08-25T15:52:59.296979+02:00][splashsurf::reconstruction][INFO] Writing surface mesh to "/home/floeschner/programming/temp/canyon_surface.xyz"... |
| 104 | +[2020-08-25T15:52:59.808101+02:00][splashsurf::reconstruction][INFO] Done. |
| 105 | +[2020-08-25T15:52:59.879069+02:00][splashsurf][INFO] Finished processing all inputs. |
| 106 | +[2020-08-25T15:52:59.879103+02:00][splashsurf][INFO] surface reconstruction cli: 100.00%, 25363.19ms/call @ 0.04Hz |
| 107 | +[2020-08-25T15:52:59.879107+02:00][splashsurf][INFO] loading particle positions: 0.55%, 139.30ms/call @ 0.04Hz |
| 108 | +[2020-08-25T15:52:59.879109+02:00][splashsurf][INFO] reconstruct_surface: 97.15%, 24641.60ms/call @ 0.04Hz |
| 109 | +[2020-08-25T15:52:59.879111+02:00][splashsurf][INFO] compute minimum enclosing aabb: 0.12%, 29.37ms/call @ 0.04Hz |
| 110 | +[2020-08-25T15:52:59.879113+02:00][splashsurf][INFO] neighborhood_search: 7.65%, 1886.10ms/call @ 0.04Hz |
| 111 | +[2020-08-25T15:52:59.879115+02:00][splashsurf][INFO] parallel_generate_cell_to_particle_map: 11.52%, 217.26ms/call @ 0.04Hz |
| 112 | +[2020-08-25T15:52:59.879117+02:00][splashsurf][INFO] get_cell_neighborhoods_par: 2.70%, 50.97ms/call @ 0.04Hz |
| 113 | +[2020-08-25T15:52:59.879119+02:00][splashsurf][INFO] calculate_particle_neighbors_par: 52.80%, 995.77ms/call @ 0.04Hz |
| 114 | +[2020-08-25T15:52:59.879121+02:00][splashsurf][INFO] parallel_compute_particle_densities: 1.12%, 275.39ms/call @ 0.04Hz |
| 115 | +[2020-08-25T15:52:59.879144+02:00][splashsurf][INFO] parallel_generate_sparse_density_map: 72.70%, 17914.09ms/call @ 0.04Hz |
| 116 | +[2020-08-25T15:52:59.879146+02:00][splashsurf][INFO] triangulate_density_map: 15.17%, 3736.97ms/call @ 0.04Hz |
| 117 | +[2020-08-25T15:52:59.879148+02:00][splashsurf][INFO] interpolate_points_to_cell_data: 95.22%, 3558.47ms/call @ 0.04Hz |
| 118 | +[2020-08-25T15:52:59.879161+02:00][splashsurf][INFO] generate_iso_surface_vertices: 69.82%, 2484.44ms/call @ 0.04Hz |
| 119 | +[2020-08-25T15:52:59.879164+02:00][splashsurf][INFO] relative_to_threshold_postprocessing: 29.70%, 1056.71ms/call @ 0.04Hz |
| 120 | +[2020-08-25T15:52:59.879167+02:00][splashsurf][INFO] triangulate: 4.78%, 178.50ms/call @ 0.04Hz |
| 121 | +[2020-08-25T15:52:59.879171+02:00][splashsurf][INFO] write surface mesh to file: 2.02%, 511.21ms/call @ 0.04Hz |
105 | 122 | ``` |
106 | 123 |
|
107 | 124 | ## License |
|
0 commit comments