Skip to content

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

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

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

Conversation

@ACMLCZH

@ACMLCZH ACMLCZH commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

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]].
Comment thread genesis/ext/pyrender/shaders/mesh_normal.vert
Comment thread genesis/utils/element.py Outdated
Comment thread tests/test_fem.py Outdated
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

⚠️ Abnormal Benchmark Result Detected ➡️ Report

@ACMLCZH ACMLCZH marked this pull request as ready for review June 9, 2026 00:48
@ACMLCZH ACMLCZH requested a review from YilingQiao as a code owner June 9, 2026 00:48

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 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".

Comment thread genesis/ext/pyrender/renderer.py
ACMLCZH added 3 commits June 8, 2026 18:48
- 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.
@ACMLCZH ACMLCZH requested a review from duburcqa June 9, 2026 06:50
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