Commit Graph

14 Commits

Author SHA1 Message Date
erald ceni
a5093b158b Fix CPU marching cubes precision and topology at high resolutions (#1934) (#2043)
Summary:
Fixes https://github.com/facebookresearch/pytorch3d/issues/1934. Two independent bugs in the CPU backend.

### 1. Degenerate-triangle filter discards valid faces

`marching_cubes_cpu.cpp`, `marching_cubes.py`

`tri.clear()` and `ps.clear()` sit inside the degeneracy check, so the buffers only reset when a triangle is *accepted*. Once a cube's first triangle is degenerate, `ps[0..2]` stay frozen on it, and every subsequent triangle in that cube fails the same stale check and is dropped.

Fixed by gating on `ps.size() == 3` and clearing unconditionally. The old code could only ever drop faces, never emit incorrect ones, so this is strictly additive.

### 2. Edge hash computed in float32

`marching_cubes_utils.h`

`p[v].x/y/z` hold integral coordinates but are stored as `float`, so `x + y*W + z*W*H` evaluates entirely in float32 before truncating to `int`. float32 is exact only to 2²⁴ − 1 = 16,777,215 — and 256³ maxes out at exactly that value. At 512³ the maximum id is 134,217,727, where float32 spacing is 8, so distinct vertices collide on one id and `uniq_edge_id` merges them.

Fixed by widening `W/H/D` to `int64_t` and casting each coordinate before multiplying. Also tightens the stride from `(W + W*H + W*H*D)` to `W*H*D`. Raises the CPU ceiling from 256³ to 1448³.

Scope is the CPU path only. `marching_cubes_naive` was never affected (Python ints are arbitrary-precision), and neither was CUDA: `hashVpair` there computes ids in `uint` rather than `float`, so it has no 2²⁴ cliff, and `MarchingCubes` already rejects volumes above 1024³ before the CUDA kernel runs. The new `TORCH_CHECK` bound and the "~1448³" note in the new comments describe `MarchingCubesCpu` only.

### Verification

Ellipsoid SDF (0.1, 1, 1), `isolevel=0.0`, identical input tensors on both devices.

| Resolution | CUDA V | CUDA F | CPU V | CPU F | Degenerate dropped |
| -- | -- | -- | -- | -- | -- |
| 32³ | 1,664 | 3,324 | 1,664 | 3,324 | 0 |
| 64³ | 7,312 | 14,620 | 7,312 | 14,620 | 0 |
| 128³ | 30,168 | 60,332 | 30,168 | 60,332 | 0 |
| 256³ | 122,448 | 244,892 | 122,448 | 243,996 | 896 |
| 512³ | 491,944 | 983,884 | 491,944 | 976,140 | 7,744 |

Machine: Arch Linux, RTX 4080, Ryzen 7 7800X3D

Vertex counts now match CUDA exactly at every resolution; 512³ previously produced 176,121. The remaining face gap is entirely degenerate geometry — the CUDA mesh at 512³ contains exactly 7,744 zero-area triangles.

### Tests

`test_degenerate_triangle_keeps_later_faces` — a 2×2×2 volume at `isolevel=1` chosen so the cube's four candidate triangles collapse onto its four outside corners: triangles 1 and 4 become degenerate, 2 and 3 stay valid. Pre-fix, the first degeneracy suppresses the rest and the mesh comes back empty; post-fix it is the expected quad. Asserts both `marching_cubes_naive` and the C++ extension.

`test_large_grid_edge_ids` — a 2×2×4,200,000 volume (~67MB, ~0.1s) holding 16 isolated interior points on the highest-id grid row, positioned so grid-point ids straddle 2²⁴. Each point cuts exactly four grid edges, so the 64-vertex expectation is derived geometrically rather than copied from output. Pre-fix, a hash collision merges two edges and one vertex is lost.

All 26 pre-existing tests in `test_marching_cubes.py` pass **unchanged**. That includes `test_cube_no_duplicate_verts` (`isolevel=1`) and `test_sphere` (`isolevel=64`), which both exercise the degenerate path but whose output is identical before and after the fix — so no existing expectation was edited and `sphere_level64.pickle` does not need regenerating.

The imported diff contained no test file. The two tests above were written during import and differ from the tests described in the upstream PR description.

*Analysis and write-up done collaboratively with AI, figures from testing are done on my own machine and have been checked.*

Pull Request resolved: https://github.com/facebookresearch/pytorch3d/pull/2043

Test Plan:
```
buck2 test fbcode//vision/fair/pytorch3d:tests -- --regex 'test_marching_cubes'
```

`Pass 28. Fail 0.` — 26 pre-existing tests plus the 2 new regression tests.

Reverting all three source hunks to their pre-fix state and re-running the same command: both new tests fail (`test_degenerate_triangle_keeps_later_faces` returns an empty mesh instead of 4 verts / 2 faces; `test_large_grid_edge_ids` returns 31 verts instead of 32) and all 26 pre-existing tests still pass. The new tests are therefore pinned to exactly this change, and the change breaks nothing that was already covered.

Reviewed By: MichaelRamamonjisoa

Differential Revision: D115424433

Pulled By: bottler

fbshipit-source-id: 547a260010b94253f52f3a3c223d4c4fa78a7ee6
2026-08-17 06:49:38 -07:00
Thomas Polasek
055ab3a2e3 Convert directory fbcode/vision to use the Ruff Formatter
Summary:
Converts the directory specified to use the Ruff formatter in pyfmt

ruff_dog

If this diff causes merge conflicts when rebasing, please run
`hg status -n -0 --change . -I '**/*.{py,pyi}' | xargs -0 arc pyfmt`
on your diff, and amend any changes before rebasing onto latest.
That should help reduce or eliminate any merge conflicts.

allow-large-files

Reviewed By: bottler

Differential Revision: D66472063

fbshipit-source-id: 35841cb397e4f8e066e2159550d2f56b403b1bef
2024-11-26 02:38:20 -08:00
Ada Martin
c292c71c1a c++ marching cubes fix
Summary:
Fixes https://github.com/facebookresearch/pytorch3d/issues/1641. The bug was caused by the mistaken downcasting of an int64_t into int, causing issues only on inputs large enough to have hashes that escaped the bounds of an int32.

Also added a test case for this issue.

Reviewed By: bottler

Differential Revision: D53505370

fbshipit-source-id: 0fdd0efc6d259cc3b0263e7ff3a4ab2c648ec521
2024-02-08 11:13:15 -08:00
Jeremy Reizenstein
f613682551 marching_cubes type fix
Summary: fixes https://github.com/facebookresearch/pytorch3d/issues/1679

Reviewed By: MichaelRamamonjisoa

Differential Revision: D50949933

fbshipit-source-id: 5c467de8bf84dd2a3d61748b3846678582d24ea3
2023-11-14 07:38:54 -08:00
Jiali Duan
8b8291830e Marching Cubes cuda extension
Summary:
Torch CUDA extension for Marching Cubes
- MC involving 3 steps:
  - 1st forward pass to collect vertices and occupied state for each voxel
  - Compute compactVoxelArray to skip non-empty voxels
  - 2nd pass to genereate interpolated vertex positions and faces by marching through the grid
- In contrast to existing MC:
   - Bind each interpolated vertex with a global edge_id to address floating-point precision
   - Added deduplication process to remove redundant vertices and faces

Benchmarks (ms):

| N / V(^3)      | python          | C++             |   CUDA   | Speedup |
| 2 / 20          |    12176873  |       24338     |     4363   | 2790x/5x|
| 1 / 100          |     -             |    3070511     |   27126   |    113x    |
| 2 / 100          |     -             |    5968934     |   53129   |    112x    |
| 1 / 256          |     -             |  61278092     | 430900   |    142x    |
| 2 / 256          |     -             |125687930     | 856941   |    146x   |

Reviewed By: kjchalup

Differential Revision: D39644248

fbshipit-source-id: d679c0c79d67b98b235d12296f383d760a00042a
2022-11-15 19:42:04 -08:00
Jiali Duan
0d8608b9f9 Marching Cubes C++ torch extension
Summary:
Torch C++ extension for Marching Cubes

- Add torch C++ extension for marching cubes. Observe a speed up of ~255x-324x speed up (over varying batch sizes and spatial resolutions)

- Add C++ impl in existing unit-tests.

(Note: this ignores all push blocking failures!)

Reviewed By: kjchalup

Differential Revision: D39590638

fbshipit-source-id: e44d2852a24c2c398e5ea9db20f0dfaa1817e457
2022-10-06 11:13:53 -07:00
Jiali Duan
850efdf706 Python marching cubes improvements
Summary: Overhaul of marching_cubes_naive for better performance and to avoid relying on unstable hashing. In particular, instead of hashing vertex positions, we index each interpolated vertex with its corresponding edge in the 3d grid.

Reviewed By: kjchalup

Differential Revision: D39419642

fbshipit-source-id: b5fede3525c545d1d374198928dfb216262f0ec0
2022-10-06 11:08:49 -07:00
Jeremy Reizenstein
34f648ede0 move targets
Summary: Move testing targets from pytorch3d/tests/TARGETS to pytorch3d/TARGETS.

Reviewed By: shapovalov

Differential Revision: D36186940

fbshipit-source-id: a4c52c4d99351f885e2b0bf870532d530324039b
2022-05-25 06:16:03 -07:00
Tim Hatch
34bbb3ad32 apply import merging for fbcode/vision/fair (2 of 2)
Summary:
Applies new import merging and sorting from µsort v1.0.

When merging imports, µsort will make a best-effort to move associated
comments to match merged elements, but there are known limitations due to
the diynamic nature of Python and developer tooling. These changes should
not produce any dangerous runtime changes, but may require touch-ups to
satisfy linters and other tooling.

Note that µsort uses case-insensitive, lexicographical sorting, which
results in a different ordering compared to isort. This provides a more
consistent sorting order, matching the case-insensitive order used when
sorting import statements by module name, and ensures that "frog", "FROG",
and "Frog" always sort next to each other.

For details on µsort's sorting and merging semantics, see the user guide:
https://usort.readthedocs.io/en/stable/guide.html#sorting

Reviewed By: bottler

Differential Revision: D35553814

fbshipit-source-id: be49bdb6a4c25264ff8d4db3a601f18736d17be1
2022-04-13 06:51:33 -07:00
Jeremy Reizenstein
9eeb456e82 Update license for company name
Summary: Update all FB license strings to the new format.

Reviewed By: patricklabatut

Differential Revision: D33403538

fbshipit-source-id: 97a4596c5c888f3c54f44456dc07e718a387a02c
2022-01-04 11:43:38 -08:00
Patrick Labatut
af93f34834 License lint codebase
Summary: License lint codebase

Reviewed By: theschnitz

Differential Revision: D29001799

fbshipit-source-id: 5c59869911785b0181b1663bbf430bc8b7fb2909
2021-06-22 03:45:27 -07:00
Rong Rong (AI Infra)
dd8343922e Get rid of duplicate test data directory initialization
Summary: Simplify finding the data directories in the tests.

Reviewed By: nikhilaravi

Differential Revision: D27634293

fbshipit-source-id: dc308a7c86c41e6fae56a2ab58187c9f0335b575
2021-04-08 20:03:04 -07:00
Rong Rong (AI Infra)
1216b5765a Extract finding directories for test data
Summary: Make common functions for finding directories where test data is found, instead of lots of tests using their own `__file__`  while trying to get ./tests/data and the tutorials data.

Reviewed By: nikhilaravi

Differential Revision: D27633701

fbshipit-source-id: 1467bb6018cea16eba3cab097d713116d51071e9
2021-04-08 20:03:04 -07:00
Nikhila Ravi
ebac66daeb Classic Marching Cubes algorithm implementation
Summary:
Defines a function to run marching cubes algorithm on a single or batch of 3D scalar fields. Returns a mesh's faces and vertices.

UPDATES (12/18)
- Input data is now specified as a (B, D, H, W) tensor as opposed to a (B, W, H, D) tensor. This will now be compatible with the Volumes datastructure.
- Add an option to return output vertices in local coordinates instead of world coordinates.
Also added a small fix to remove the dype for device in Transforms3D - if passing in a torch.device instead of str it causes a pyre error.

Reviewed By: jcjohnson

Differential Revision: D24599019

fbshipit-source-id: 90554a200319fed8736a12371cc349e7108aacd0
2020-12-18 07:25:50 -08:00