Summary:
Fixes the coordinate indexing used by frustum face culling, and keeps the now-live culling from deleting faces that straddle the camera plane.
`face_verts` has shape `[F, 3, 3]`, where the last two dimensions are the vertex and the xyz coordinate. `_get_culled_faces` indexed it as `face_verts[:, axis]`, which picks one whole vertex out of every face rather than one coordinate out of all three vertices, so `verts_clipped.sum(1) == 3` was asking whether a single vertex was outside the plane on all three axes at once. Every other access in the file agrees with the documented layout — `clip_faces` reads z as `face_verts_unclipped[:, :, 2]`. The fix selects the coordinate with `face_verts[:, :, axis]` and reduces with `all(dim=1)`, which states the documented condition directly: a face is culled only when all three of its vertices lie outside the same plane.
Because the old indexing almost never fired, this is the first time frustum culling does real work, and that exposes a second problem. `_get_culled_faces` runs on the unclipped face verts, and `rasterize_meshes` passes `left`/`right`/`top`/`bottom` in NDC while z stays in world space. The perspective divide mirrors vertices behind the camera through the origin, so a triangle straddling the camera plane can have all 3 projected vertices outside the same xy plane while the part of it in front of the camera still crosses the frustum. At fov 90, for instance, the vertices `(-1.1, 0, 1)`, `(100, 0, -1)` and `(100, 0.1, -1)` all project to x < -1, yet the edge from the first to the second passes through x = 0 while still at z > 0. Culled faces are classified as case 2 and dropped outright, before z clipping could have salvaged them, so that triangle would vanish from the render.
xy culling is therefore now applied only to faces lying entirely in front of the clipping plane (`z >= z_clip_value`, or `z > 0` when no clip value is set), and only when `perspective_correct` is set; straddling faces are left to the z clipping step. Orthographic projections keep usable xy coordinates behind the camera and are unaffected, as is culling on the z axis, which uses world coordinates throughout. The `frustum.cull` check also moves out of the per-plane loop into an early return.
For blast radius: `RasterizationSettings.cull_to_frustum` defaults to `False`, but `rasterize_meshes_python` defaults it to `True`.
Fixes https://github.com/facebookresearch/pytorch3d/issues/1936.
Pull Request resolved: https://github.com/facebookresearch/pytorch3d/pull/2044
Test Plan:
`buck2 test fbcode//vision/fair/pytorch3d:tests`, filtered to the culling and rendering tests (`--regex 'test_render_meshes_clipped|test_render_meshes\b|clip'`): 34 passed, 0 failed, 8 skipped. The skips are the OpenGL-only tests.
Two new unit tests over `_get_culled_faces`:
- `test_cull_faces_uses_coordinate_axis` — for each of the 6 planes, a face whose 3 vertices all lie outside it is culled; and a face intersecting the left plane stays visible for 3 different vertex orders. Fails on the old `face_verts[:, axis]` indexing.
- `test_cull_faces_straddling_perspective_camera` — a face with one vertex in front of the camera and two behind it, all 3 projecting outside the left plane, is not culled under a perspective projection (with and without a `z_clip_value`) but is culled under an orthographic one; and z-axis culling still fires for a face lying entirely behind `znear`. Negative control: with the xy gating disabled and nothing else changed, this test fails on 2 assertions, so it pins the new behaviour rather than restating it.
`arc lint` on `pytorch3d/renderer/mesh/clip.py` and `tests/test_render_meshes_clipped.py`: no issues.
Reviewed By: MichaelRamamonjisoa
Differential Revision: D117200371
Pulled By: bottler
fbshipit-source-id: 99422fc69f4f5725bd82f6af205a0a333a4aef40
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
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
Summary: Update all FB license strings to the new format.
Reviewed By: patricklabatut
Differential Revision: D33403538
fbshipit-source-id: 97a4596c5c888f3c54f44456dc07e718a387a02c
Summary:
Change the cow gltf loading test to validate the texture values and not to validate the renderer output because it has an unstable pixel.
Also a couple of lints.
Reviewed By: patricklabatut
Differential Revision: D29131260
fbshipit-source-id: 5e11f066a2a638588aacb09776cc842173ef669f
Summary:
There was a bug when `z_clip_value` is not None but there are no faces which are actually visible in the image due to culling. In `rasterize_meshes.py` a function `convert_clipped_rasterization_to_original_faces` is called to convert the clipped face indices etc back to the unclipped versions, but the case where there is no clipping was not handled correctly.
Fixes Github Issue #632
Reviewed By: bottler
Differential Revision: D29116150
fbshipit-source-id: fae82a0b4848c84b3ed7c7b04ef5c9848352cf5c
Summary:
When `z_clip_value = None` and faces are outside the view frustum the shape of one of the tensors in `clip.py` is incorrect.
`faces_num_clipped_verts` should be (F,) but it was (F,3). Added a new test to ensure this case is handled.
Reviewed By: bottler
Differential Revision: D29051282
fbshipit-source-id: 5f4172ba4d4a75d928404dde9abf48aef18c68bd
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
Summary:
- Updated the C++/CUDA mesh rasterization kernels to handle the clipped faces. In particular this required careful handling of the distance calculation for faces which are cut into a quadrilateral by the image plane and then split into two sub triangles i.e. both sub triangles can't be part of the top K faces.
- Updated `rasterize_meshes.py` to use the utils functions to clip the meshes and convert the fragments back to in terms of the unclipped mesh
- Added end to end tests
Reviewed By: jcjohnson
Differential Revision: D26169685
fbshipit-source-id: d64cd0d656109b965f44a35c301b7c81f451cfa0
Summary:
Instead of culling faces behind the camera, partially clip them if they intersect with the image plane.
This diff implements the utils functions for clipping.
There are 4 cases for the mesh faces which are all handled:
```
Case 1: the triangle is completely in front of the clipping plane (it is left
unchanged)
Case 2: the triangle is completely behind the clipping plane (it is culled)
Case 3: the triangle has exactly two vertices behind the clipping plane (it is
clipped into a smaller triangle)
Case 4: the triangle has exactly one vertex behind the clipping plane (it is clipped
into a smaller quadrilateral and divided into two triangular faces)
```
Reviewed By: jcjohnson
Differential Revision: D23108673
fbshipit-source-id: 550a8b6a982d06065dff10aba10d47e8b144ae52