Skip to content

[FEATURE] Decouple FEM render geometry from sim geometry (multi-sub-mesh + double-sided normal pass)#2904

Draft
ACMLCZH wants to merge 7 commits into
Genesis-Embodied-AI:mainfrom
ACMLCZH:pr/fem-render-meshes
Draft

[FEATURE] Decouple FEM render geometry from sim geometry (multi-sub-mesh + double-sided normal pass)#2904
ACMLCZH wants to merge 7 commits into
Genesis-Embodied-AI:mainfrom
ACMLCZH:pr/fem-render-meshes

Conversation

@ACMLCZH
Copy link
Copy Markdown
Collaborator

@ACMLCZH ACMLCZH commented Jun 5, 2026

Summary

Decouple FEM rendering geometry from simulation geometry.

  • Each FEMEntity now carries render_meshes: list[gs.Mesh] and sim_vert_maps: list[np.ndarray].
  • sim_vert_maps is used to map rendering vertices in render_meshes to simulation vertices from FEMSolver.
  • It can perfectly preserve surfaces (textures and UVs) from multi-geom assets.
  • Now FEMEntity also support segmentation in geom level.

[BUG FIX] Support double-sided normal shader for pyrender

  • Previously the normal shader of pyrender is not double-sided.

Visual

Pair 1 — Ducks (Left Rigid, Right FEM)

Before After (This PR)
sbs_upstream sbs_ours

Pair 2 — multi-geom FEM rendering (Trashbag_rope.glb)

Before (uniform single surface) After (per-sub-mesh GLB materials)
trashbag_before trashbag_after

Before: a uniform user-supplied surface is applied to the whole entity — what the pre-PR solver-side rendering produced (one entity.surface for all sub-meshes). After: each sub-mesh keeps its own GLB material via render_meshes — the channel's yellow rim is now distinct from the bag body.

Snapshots

  • Genesis-Intelligence/snapshots updated → 4910d05d2a40de6890263bf92376b389d660d7fb (6 PNGs across 2 commits).
  • tests/utils.py: HUGGINGFACE_SNAPSHOT_REVISION bumped to match.

Next Step

  • Make Nyx support render_meshes.
  • Fix "dual write" primitive buffer in pyrender.
  • Make other deformables also support 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; updated test_segmentation_map formula at "geom" level accounts for per-sub-mesh FEM seg tuples.

ACMLCZH added 5 commits June 5, 2026 11:11
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]].
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reduce the diff. It should not be this large. You made something wrong in your commit.

Comment thread genesis/utils/element.py
def mesh_to_elements(mesh, tet_cfg=dict()):
tet_file_path = mu.get_tet_path(mesh.vertices, mesh.faces, tet_cfg)

# loading pre-computed cache if available
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not remove comments that are still applicable.

Comment thread tests/test_fem.py Outdated
Comment on lines +90 to +98
# Verify that the visualizer mesh's vertices correctly track the FEM sim's
# surface vertices through `fem.sim_vert_maps`. The visualizer mesh
# (`render_meshes[0]`) holds the *pre-tet-split* input surface (e.g. 12 box
# triangles), while `fem.surface_triangles` is computed from the *post-split*
# tetrahedral elements (with mid-edge Steiner subdivisions). The two meshes
# differ in granularity *by design* — so comparing triangle sets is not the
# right invariant. The correct invariant is that the renderer's per-vertex
# buffer updates from `sim_verts[svm]` produce vertex positions consistent
# with the sim state.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are wrapping comments too early.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants