[FEATURE] Decouple FEM render geometry from sim geometry (multi-sub-mesh + double-sided normal pass)#2904
Open
ACMLCZH wants to merge 12 commits into
Open
[FEATURE] Decouple FEM render geometry from sim geometry (multi-sub-mesh + double-sided normal pass)#2904ACMLCZH wants to merge 12 commits into
ACMLCZH wants to merge 12 commits into
Conversation
Introduce a `render_meshes` + `sim_vert_maps` model on FEMEntity so the visualizer can draw the user's original input surface (multi-sub-mesh GLBs supported) while the FEM solver retains its own tet-boundary topology for physics. Changes: - FEMEntity.sample() builds `_render_meshes` (list[gs.Mesh]) and `_sim_vert_maps` (list[np.ndarray]) via `gs.Mesh.from_morph_surface` and a new `_merge_elements` helper that dedupes vertices across sub-meshes and remaps element indices. - FEM solver drops the `surface_render_f` (triangle-indices) and `surface_render_uvs` (per-vertex UV) fields; rendering topology / UVs now live on FEMEntity's per-sub-mesh `Mesh` objects. - `get_state_render(f)` returns sim vertex positions only. - Rasterizer + raytracer iterate per-sub-mesh and key static nodes by `(env_idx, entity.uid, sub_idx)`. - `mesh_to_elements` signature change: accepts a trimesh directly, returns (verts, elems) only (UVs come from the input render mesh). - `gs.Mesh.from_morph_surface` returns a list for primitive morphs too — uniform return type makes consumers simpler. - `test_interior_tetrahedralized_vertex` updated to assert the new invariant: viz vertices = sim_verts[sim_vert_maps[0]].
…-world into pr/fem-render-meshes
duburcqa
reviewed
Jun 6, 2026
duburcqa
reviewed
Jun 6, 2026
duburcqa
reviewed
Jun 6, 2026
|
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 063d6bc580
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
- FEM `morph.pos` now applied as float64 in `instantiate`; gs.np_float (float32) quantizes 0.4/-0.1/0.1 etc. and perturbs downstream coords enough to push the macOS `linear_corotated` falling-sphere rest-state assertion over its tolerance. - `_merge_elements` no longer downcasts merged verts to gs.np_float; tetgen is sensitive to vertex coord precision and the downcast-then-upcast loses ULPs vs the upstream float64 path. - `split_all_surface_tets` is now applied only to file-loaded `Mesh` morphs (matching upstream); calling it for `Sphere`/`Box`/`Cylinder` primitives changed tet topology vs upstream. - Viewer's normal-pass `CustomShaderCache` strips the `DOUBLE_SIDED` define before compiling. Without the matching geometry shader, `mesh_normal.vert` emits `v_frag_*` while `mesh_normal.frag` expects `frag_*`, breaking shader linking on GUI normal captures of double-sided primitives.
The previous fix (commit 14e6d7c) only changed the float32→float64 dtype of `p` in `instantiate`, but left tetgen seeing the centered (un-translated) mesh. Tetgen's Steiner-point insertion is sensitive to absolute coords: - Centered sphere → 960 verts / 3726 elems - Sphere translated to (0.4, -0.1, 0.1) → 968 verts / 3784 elems ← upstream The mesh-count delta cascaded through the implicit FEM integrator on macOS and pushed `test_implicit_falling_sphere_box[SAP-linear_corotated-64]`'s 0.025 rest-state tolerance over by ~12% (90/2973 vertices violating). Apply pos to the merged surface verts in `sample` (before tetgen runs), and remove the duplicate translation from `instantiate`. The tet mesh now matches upstream's `sphere_to_elements` / `box_to_elements` output byte-for-byte.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Decouple FEM rendering geometry from simulation geometry.
FEMEntitynow carriesrender_meshes: list[gs.Mesh]andsim_vert_maps: list[np.ndarray].sim_vert_mapsis used to map rendering vertices inrender_meshesto simulation vertices fromFEMSolver.FEMEntityalso support segmentation ingeomlevel.[BUG FIX] Support double-sided normal shader for pyrender
Visual
Pair 1 — Ducks (Left Rigid, Right FEM)
Pair 2 — multi-geom FEM rendering (Trashbag_rope.glb)
Before: a uniform user-supplied surface is applied to the whole entity — what the pre-PR solver-side rendering produced (one
entity.surfacefor all sub-meshes). After: each sub-mesh keeps its own GLB material viarender_meshes— the channel's yellow rim is now distinct from the bag body.Snapshots
Genesis-Intelligence/snapshotsupdated →4910d05d2a40de6890263bf92376b389d660d7fb(6 PNGs across 2 commits).tests/utils.py:HUGGINGFACE_SNAPSHOT_REVISIONbumped to match.Next Step
render_meshes.render_meshes.Test plan
pytest tests/test_fem.py— all 6 parametrizes pass against the new render_meshes structure.pytest tests/test_render.py— 64 passed; the multi-sub-mesh FEM render snapshots (rgb/depth/seg/normal) pass via HF revision pin; updatedtest_segmentation_mapformula at"geom"level accounts for per-sub-mesh FEM seg tuples.