├── .cargo └── config.toml ├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ ├── codecov.yml │ └── release.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── client.gif ├── index.html ├── mesh_to_sdf ├── ARCHITECTURE.md ├── CHANGELOG.md ├── Cargo.toml ├── README.md ├── assets │ ├── FlightHelmet.glb │ ├── README.md │ ├── annoted_cube.glb │ ├── ferris3d.glb │ ├── knight.glb │ └── suzanne.glb ├── benches │ ├── generate_grid_sdf.rs │ └── generate_sdf.rs ├── examples │ └── demo.rs ├── proptest-regressions │ └── geo.txt ├── src │ ├── bvh_ext.rs │ ├── generate │ │ ├── generic │ │ │ ├── bvh.rs │ │ │ ├── default.rs │ │ │ ├── mod.rs │ │ │ ├── rtree.rs │ │ │ └── rtree_bvh.rs │ │ ├── grid.rs │ │ └── mod.rs │ ├── geo.rs │ ├── grid.rs │ ├── lib.rs │ ├── point.rs │ ├── point │ │ ├── impl_array.rs │ │ ├── impl_cgmath.rs │ │ ├── impl_glam.rs │ │ ├── impl_mint.rs │ │ └── impl_nalgebra.rs │ └── serde.rs └── tests │ ├── generate_python_baseline.py │ ├── sdf_generic_v1.bin │ └── sdf_grid_v1.bin ├── mesh_to_sdf_client ├── ARCHITECTURE.md ├── CHANGELOG.md ├── Cargo.toml ├── README.md ├── shaders │ ├── draw_cubemap.wgsl │ ├── draw_model.wgsl │ ├── draw_raymarching.wgsl │ ├── draw_sdf.wgsl │ ├── draw_shadowmap.wgsl │ ├── draw_voxels.wgsl │ └── utility │ │ └── mipmap_generation.wgsl ├── src │ ├── camera.rs │ ├── camera_control.rs │ ├── cubemap.rs │ ├── frame_rate.rs │ ├── gltf │ │ ├── mod.rs │ │ ├── scene │ │ │ ├── camera.rs │ │ │ ├── light.rs │ │ │ ├── mod.rs │ │ │ └── model │ │ │ │ ├── material │ │ │ │ ├── emissive.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── normal.rs │ │ │ │ ├── occlusion.rs │ │ │ │ └── pbr.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── mode.rs │ │ │ │ └── vertex.rs │ │ └── utils │ │ │ ├── gltf_data.rs │ │ │ └── mod.rs │ ├── main.rs │ ├── passes │ │ ├── cubemap_generation_pass.rs │ │ ├── mip_generation_pass.rs │ │ ├── mod.rs │ │ ├── model_render_pass.rs │ │ ├── raymarch_pass.rs │ │ ├── sdf_render_pass.rs │ │ ├── shadow_pass.rs │ │ └── voxel_render_pass.rs │ ├── pbr │ │ ├── mesh.rs │ │ ├── mesh │ │ │ └── primitives.rs │ │ ├── mod.rs │ │ ├── model.rs │ │ ├── model_instance.rs │ │ └── shadow_map.rs │ ├── reload_flags.rs │ ├── runner.rs │ ├── sdf.rs │ ├── sdf_program.rs │ ├── sdf_program │ │ ├── command_stack.rs │ │ └── ui.rs │ ├── texture.rs │ └── utility │ │ ├── mip_generation.rs │ │ ├── mod.rs │ │ └── shader_builder.rs └── tests │ ├── box_sparse.glb │ ├── complete.glb │ ├── cube.glb │ ├── cube.png │ ├── cube_classic.bin │ ├── cube_classic.gltf │ ├── dragon.glb │ ├── head.glb │ └── suzanne.glb └── update_web.bat /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | # Required to avoid a linker error on Windows when building the dylib. 2 | [target.x86_64-pc-windows-msvc] 3 | # linker = "rust-lld.exe" 4 | # rustflags = ["-Zshare-generics=n"] 5 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "cargo" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | - package-ecosystem: "github-actions" 13 | directory: "/" 14 | schedule: 15 | interval: "weekly" 16 | labels: 17 | - "dependencies" 18 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI # Continuous Integration 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | 7 | test: 8 | name: Test Suite 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Update ubuntu 12 | run: sudo apt-get update -y 13 | - name: Install libgtk for rfd 14 | run: sudo apt-get install -y libgtk-3-dev 15 | - name: Checkout repository 16 | uses: actions/checkout@v4 17 | - name: Install Rust toolchain 18 | uses: dtolnay/rust-toolchain@stable 19 | - uses: Swatinem/rust-cache@v2 20 | - name: Run tests 21 | run: cargo test --all-features --workspace 22 | 23 | rustfmt: 24 | name: Rustfmt 25 | runs-on: ubuntu-latest 26 | steps: 27 | - name: Update ubuntu 28 | run: sudo apt-get update -y 29 | - name: Install libgtk for rfd 30 | run: sudo apt-get install -y libgtk-3-dev 31 | - name: Checkout repository 32 | uses: actions/checkout@v4 33 | - name: Install Rust toolchain 34 | uses: dtolnay/rust-toolchain@stable 35 | with: 36 | components: rustfmt 37 | - uses: Swatinem/rust-cache@v2 38 | - name: Check formatting 39 | run: cargo fmt --all --check 40 | 41 | clippy: 42 | name: Clippy 43 | runs-on: ubuntu-latest 44 | steps: 45 | - name: Update ubuntu 46 | run: sudo apt-get update -y 47 | - name: Install libgtk for rfd 48 | run: sudo apt-get install -y libgtk-3-dev 49 | - name: Checkout repository 50 | uses: actions/checkout@v4 51 | - name: Install Rust toolchain 52 | uses: dtolnay/rust-toolchain@stable 53 | with: 54 | components: clippy 55 | - uses: Swatinem/rust-cache@v2 56 | - name: Clippy check 57 | run: cargo clippy --all-features --workspace 58 | 59 | docs: 60 | name: Docs 61 | runs-on: ubuntu-latest 62 | steps: 63 | - name: Update ubuntu 64 | run: sudo apt-get update -y 65 | - name: Install libgtk for rfd 66 | run: sudo apt-get install -y libgtk-3-dev 67 | - name: Checkout repository 68 | uses: actions/checkout@v4 69 | - name: Install Rust toolchain 70 | uses: dtolnay/rust-toolchain@stable 71 | - uses: Swatinem/rust-cache@v2 72 | - name: Check documentation 73 | env: 74 | RUSTDOCFLAGS: -D warnings 75 | run: cargo doc --no-deps --document-private-items --all-features --workspace 76 | 77 | hack: 78 | name: Check 79 | runs-on: ubuntu-latest 80 | steps: 81 | - name: Update ubuntu 82 | run: sudo apt-get update -y 83 | - name: Install libgtk for rfd 84 | run: sudo apt-get install -y libgtk-3-dev 85 | - uses: actions/checkout@v4 86 | with: 87 | submodules: true 88 | - name: Install stable 89 | uses: dtolnay/rust-toolchain@stable 90 | - name: cargo install cargo-hack 91 | uses: taiki-e/install-action@cargo-hack 92 | - uses: Swatinem/rust-cache@v2 93 | - name: Check for all features 94 | run: cargo hack --feature-powerset check 95 | 96 | # wasm: 97 | # name: Wasm 98 | # runs-on: ubuntu-latest 99 | # steps: 100 | # - name: Update ubuntu 101 | # run: sudo apt-get update -y 102 | # - name: Install libgtk for rfd 103 | # run: sudo apt-get install -y libgtk-3-dev 104 | # - uses: actions/checkout@v4 105 | # with: 106 | # submodules: true 107 | # - name: Install stable 108 | # uses: dtolnay/rust-toolchain@stable 109 | # with: 110 | # target: wasm32-unknown-unknown 111 | # - uses: Swatinem/rust-cache@v2 112 | # - name: Check for target wasm webgpu 113 | # env: 114 | # RUSTFLAGS: --cfg=web_sys_unstable_apis 115 | # run: cargo check --target wasm32-unknown-unknown 116 | -------------------------------------------------------------------------------- /.github/workflows/codecov.yml: -------------------------------------------------------------------------------- 1 | name: Coverage 2 | 3 | on: 4 | push: 5 | branches: 6 | - '**' 7 | - '!dependabot/**' 8 | pull_request_target: 9 | 10 | jobs: 11 | coverage: 12 | runs-on: ubuntu-latest 13 | env: 14 | CARGO_TERM_COLOR: always 15 | steps: 16 | - uses: actions/checkout@v4 17 | - name: Install Rust 18 | run: rustup update stable 19 | - name: Install cargo-llvm-cov 20 | uses: taiki-e/install-action@cargo-llvm-cov 21 | - name: Generate code coverage 22 | run: cargo llvm-cov --all-features --package mesh_to_sdf --lcov --output-path lcov.info 23 | - name: Upload coverage to Codecov 24 | uses: codecov/codecov-action@v4 25 | with: 26 | files: lcov.info 27 | fail_ci_if_error: true 28 | token: ${{ secrets.CODECOV_TOKEN }} 29 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | release: 3 | types: [created] 4 | 5 | jobs: 6 | release: 7 | name: release ${{ matrix.target }} 8 | runs-on: ubuntu-latest 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | include: 13 | - target: x86_64-pc-windows-gnu 14 | archive: zip 15 | - target: x86_64-unknown-linux-musl 16 | archive: tar.gz tar.xz tar.zst 17 | - target: x86_64-apple-darwin 18 | archive: zip 19 | steps: 20 | - uses: actions/checkout@master 21 | - name: Compile and release 22 | uses: rust-build/rust-build.action@v1.4.5 23 | env: 24 | SRC_DIR: "mesh_to_sdf_client" 25 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | TOOLCHAIN_VERSION: 1.74 # 1.75 does not work with x86_64-apple-darwin yet. 27 | ARGS: --locked --release 28 | with: 29 | RUSTTARGET: ${{ matrix.target }} 30 | ARCHIVE_TYPES: ${{ matrix.archive }} 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | mutants.out 3 | mutants.out.old 4 | .vscode/launch.json 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = ["mesh_to_sdf", "mesh_to_sdf_client"] 4 | 5 | [workspace.package] 6 | edition = "2021" 7 | license = "MIT OR Apache-2.0" 8 | version = "0.2.1" 9 | 10 | 11 | [profile.release-with-debug] 12 | inherits = "release" 13 | debug = true 14 | 15 | [workspace.lints.rust] 16 | dead_code = "allow" 17 | missing_docs = "warn" 18 | unexpected_cfgs = "warn" 19 | 20 | [workspace.lints.clippy] 21 | all = { level = "warn", priority = -1 } 22 | pedantic = { level = "warn", priority = -1 } 23 | nursery = { level = "warn", priority = -1 } 24 | complexity = {level = "warn", priority = -1 } 25 | style = { level = "warn", priority = -1 } 26 | 27 | significant_drop_tightening = "allow" 28 | module_name_repetitions = "allow" 29 | cast_sign_loss = "allow" 30 | cast_precision_loss = "allow" 31 | cast_possible_truncation = "allow" 32 | missing_errors_doc = "allow" 33 | missing_panics_doc = "allow" 34 | 35 | # From restriction 36 | same_name_method = "allow" # because of rust embed, see https://github.com/pyrossh/rust-embed/issues/204 37 | std_instead_of_core = "warn" 38 | clone_on_ref_ptr = "warn" 39 | renamed_function_params = "warn" 40 | #unseparated_literal_suffix = "warn" 41 | redundant_type_annotations = "warn" 42 | partial_pub_fields = "warn" 43 | let_underscore_untyped = "warn" 44 | let_underscore_must_use = "warn" 45 | ref_patterns = "warn" 46 | undocumented_unsafe_blocks = "warn" 47 | wildcard_enum_match_arm = "warn" 48 | suboptimal_flops = "allow" 49 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /client.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azkellas/mesh_to_sdf/beea42bf76132ce0bda70e15c60adcb82677dd0e/client.gif -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /mesh_to_sdf/ARCHITECTURE.md: -------------------------------------------------------------------------------- 1 | ## Mesh to SDF 2 | 3 | `generate_sdf` bruteforces the closest point on the mesh for each query point by checking the distance to each triangle, using `rayon` to parallelize the computation. Further work would be to use a spatial data structure (e.g. bvh) to speed up the computation, and letting the user choose the algorithm (since a bvh requires memory that grows linearly with the number of triangles). 4 | 5 | `generate_grid_sdf` uses a binary heap to keep track of the closest triangle for each cell. At initialization, the heap is filled with the closest triangle for each cell. Then, the heap is iteratively updated by checking the distance to the closest triangle for each cell, until the heap is empty. 6 | 7 | *Determining sign*: currently the only method is to check the normals of the triangles. A robust method is needed, via raycasting for example. Raycasting can be optimized for the grid by aligning the rays with the grid axes. 8 | 9 | Point - triangles methods can be optimized further. -------------------------------------------------------------------------------- /mesh_to_sdf/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.4.0] - 2024-09-17 4 | 5 | ### Added 6 | 7 | - New `AccelerationMethod`s with `Rtree` and `RtreeBvh`. `Rtree` uses a r-tree for distances and the normal sign method, while `RtreeBvh` uses a r-tree for distances and a bvh for raycast. 8 | Both are about 4x faster than the previous `Bvh` for 10k and more queries. 9 | 10 | ### Changed 11 | 12 | - `generate_grid_sdf` is now fully parallelized. It's between 10x and 20x faster on a high end cpu, depending on the number of triangles and the grid resolution. 13 | - `AccelerationMethod` now includes the `SignMethod` when it makes sense. `generate_sdf` only takes the `AccelerationMethod` parameter, and the `SignMethod` is inferred from it. 14 | This is because not all acceleration methods support all sign methods. For example, `Rtree` only supports the normal sign method, while `RtreeBvh` supports raycasting only. 15 | - `Point` trait now requires `Debug` and `PartialEq` to be implemented. 16 | - `RtreeBvh` is the new default `AccelerationMethod`. 17 | 18 | 19 | ## [0.3.0] - 2024-09-06 20 | 21 | ### Added 22 | 23 | - `generate_sdf` takes an additional `AccelerationMethod` parameter, that can be either `AccelerationMethod::Bvh` (default) or `AccelerationMethod::None`. 24 | `Bvh` is recommended unless you're really tight on memory or your query is very small (couple hundreds of queries and triangles). 25 | For example, a query of 15k points with 100k triangles is 10 times faster with a bvh, and twice faster for 500 queries and 10k triangles. 26 | `Bvh` is also optimised for the `SignMethod::Raycast` sign method. https://github.com/Azkellas/mesh_to_sdf/pull/75 27 | - Both generic and grid based sdfs can now be (de-)serialized. Use `SerializeGrid` and `DeserializeGrid`, or the helpers `save_to_file` and `read_from_file`. 28 | 29 | ### Fixed 30 | 31 | - Fix https://github.com/Azkellas/mesh_to_sdf/issues/25 where `generate_grid_sdf` might panic if the grid does not contain the mesh. 32 | - Make grid based generation ~2x faster by improving heap generation. 33 | 34 | ### Removed 35 | 36 | - nalgebra is no longer optional as it is required by bvh. The feature was removed as it will always be available. 37 | 38 | 39 | ## [0.2.1] - 2024-02-18 40 | 41 | ### Changed 42 | 43 | - `generate_grid_sdf` with `SignMethod::Raycast` now tests in the three directions (+x, +y, +z). This does not slow the computation down, but it makes the result more robust. This does not affect `generate_sdf`. 44 | - `Grid::from_bounding_box` takes a `[usize; 3]` instead of `&[usize; 3]` for `cell_count` 45 | 46 | 47 | ## [0.2.0] - 2024-02-16 48 | 49 | ### Added 50 | 51 | - `SignMethod` enum to represent the sign method used to calculate the signed distance. 52 | - `generate_sdf` and `generate_grid_sdf` now take a `SignMethod` parameter. 53 | - `SignMethod::Raycast` to use raycasting to determine the sign of the distance. 54 | 55 | ## [0.1.0] - 2024-02-05 56 | 57 | First release of `mesh_to_sdf`. 58 | 59 | ### Added 60 | 61 | - `generate_sdf` function to get the signed distance from query points to a mesh. 62 | - `generate_grid_sdf` function to get the signed distance from a grid to a mesh. 63 | - `Point` trait to allow the use of any type as vertices. 64 | - `Topology` enum to represent the topology of the mesh. 65 | - `Grid` struct to represent a grid. 66 | - `[f32; 3]` implementation for `Point` trait. 67 | - `cgmath` implementation for `Point` trait. 68 | - `glam` implementation for `Point` trait. 69 | - `mint` implementation for `Point` trait. 70 | - `nalgebra` implementation for `Point` trait. 71 | -------------------------------------------------------------------------------- /mesh_to_sdf/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mesh_to_sdf" 3 | version = "0.4.0" 4 | description = "Mesh to signed distance field (SDF) converter" 5 | edition = "2021" 6 | license = "MIT OR Apache-2.0" 7 | 8 | authors = ["Etienne Desbois(tex_coords: Vec2, texture: &ImageBuffer
) -> P
149 | where
150 | P: Pixel + 'static,
151 | P::Subpixel: 'static,
152 | Container: Deref