Deformable shadow model sync to support ovphysx + ovrtx/newton_warp combinations - #6773
Conversation
Greptile SummaryThe PR adds deformable scene-data synchronization into shadow Newton models and addresses the previously reported discovery, registry, and rendering-validation gaps.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains in the reviewed fixes, and the previously reported standalone metadata, registry path, sibling discovery, visual selection, and golden-validation issues are addressed by the current code and focused tests. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart LR
USD[USD deformable geometry] --> Discovery[Deformable discovery]
PhysX[PhysX / OVPhysX nodal tensors] --> Backend[SceneDataBackend points]
Backend --> Provider[SceneDataProvider geometry mapping]
Discovery --> Shadow[Shadow Newton model and registry]
Provider --> SimBuffer[Simulation-sized particle buffer]
SimBuffer -->|direct copy| RenderBuffer[Newton particle_q render slots]
SimBuffer -->|barycentric remap| RenderBuffer
Shadow --> RenderBuffer
RenderBuffer --> Consumers[Newton Warp and OVRTX renderers]
Reviews (4): Last reviewed commit: "Document shadow deformable and SceneData..." | Re-trigger Greptile |
4578d98 to
666a1ab
Compare
There was a problem hiding this comment.
Isaac Lab Review Bot
The deformable SceneData and Newton shadow-model integration is well structured, but concrete correctness and lifecycle issues remain: shadow particle offsets can target the wrong slots when the builder already contains particles, deformable-only OVPhysX scenes skip binding setup, the changelog gives impossible migration guidance, and teardown retains the simulation particle buffer.
- Design and architecture: The backend/provider/shadow-builder split is coherent. However, shadow deformables must account for particles already present in the Newton builder; using a separate zero-based render cursor breaks synchronization for builders containing pre-existing particle data.
- API: The new SceneData properties and methods are additive with safe backend defaults. The Newton changelog incorrectly tells callers of update_visualization_state to pass allow_passthrough=True even though that method has no such parameter, so the migration guidance must be corrected.
- Implementation: OVPhysX deformable setup is currently bypassed when no rigid-body patterns are found, preventing deformable-only scenes from exporting points. Shadow render offsets ignore existing builder particles, and NewtonManager.clear() does not release the newly added _sim_particle_q device buffer.
Significant concerns. Posted 4 actionable findings inline.
Conservative automated review; human maintainers own approval decisions.
|
@isaaclab-review-bot review |
There was a problem hiding this comment.
Isaac Lab Review Bot
The dual sim/render particle layout is coherent, but two concrete issues remain: failed volume remaps can trigger an invalid direct copy, and new public Warp interfaces lack the required concrete dtype annotations.
- Design and architecture: The shared discovery and dual-buffer design is sound. However, mismatched volume meshes need an explicit safe fallback when barycentric remap construction fails.
- API: The additive SceneData geometry API is compatible, but
VolumeVisRemapandlaunch_volume_vis_remapuse genericwp.arrayannotations instead of the concrete Warp dtypes required for public interfaces. - Implementation: When a mismatched volume remap is unavailable, the render sync copies
vis_particle_countvalues directly from the sim slice. This can cross entity or buffer bounds and does not provide a valid sim-to-visual mapping; the fallback must skip the copy or use compatible sim topology.
Minor fixes needed. Posted 2 actionable findings inline.
Conservative automated review; human maintainers own approval decisions.
|
@isaaclab-review-bot review |
There was a problem hiding this comment.
Isaac Lab Review Bot
The sim-sized SceneData to vis-sized shadow-render design is reasonable, but three concrete correctness issues remain: unresolved geometry mappings collapse deformables to zero, non-environment deformables are imported twice in clone-plan scenes, and shadow mesh placement applies the deformable root transform twice.
- Design and architecture: The clone-plan builder path imports deformables outside
/World/envsthrough the top-level USD import and then adds them again through the shadow-deformable path, producing duplicate particle allocations and invalid offsets. - API: The additive SceneData point and geometry APIs are documented and retain safe backend defaults. However, geometry mapping uses exact path equality while backends may expose related child paths; unresolved mappings are not propagated to the subsequent render sync, causing skipped source slices to be treated as valid zero data.
- Implementation: Unmapped deformables have zero-initialized sim slices copied into render slots, collapsing their meshes to the origin. In addition, discovered vertices are baked into the deformable root's parent frame but are instantiated using the root pose, double-applying non-identity root transforms.
Significant concerns. Posted 3 actionable findings inline.
Conservative automated review; human maintainers own approval decisions.
|
@isaaclab-review-bot review |
35e6368 to
3058c8e
Compare
|
@isaaclab-review-bot review |
Avoid rebuilding the host-side offset set via mapping.numpy() on every update_visualization_state call. Compute it when the geometry mapping is created, and clear the offset cache whenever that mapping is rebuilt.
Share volume remaps across env clones, build barycentric tables on GPU with Warp, cache stage discovery with numpy-baked verts, and replace per-frame host scatter/copy loops with batched device kernels (SceneData, PhysX/OVPhysX merge, Newton sync).
Usd.Stage is always weak-referenceable, so drop the TypeError guard and write the discovery cache directly.
Drop redundant discovery/remap/builder cases and the destination-clamp geometry test that no longer matches the device scatter path, and fold the standalone registry-path check into the clone builder coverage.
These tests use SimpleNamespace stage stubs and only cover rigid-body binding setup, so mock discover_deformables_on_stage to avoid the weakref cache path meant for real USD stages.
Drop unused NewtonSceneDataBackend point/geometry overrides and ShadowDeformableEntity compatibility aliases introduced in this PR. Deduplicate visualization-state fixtures and keep only high-value coverage of PhysX/OVPhysX shadow sync and builder paths.
Replace the RelativeJointPositionActionCfg workaround with a small absolute EE pose nudge so motion_vectors goldens use the default DiffIK action path again. Refresh the isaaclab_tasks skip changelog fragment for this PR.
Drop the test-only file materialization and env0 export wrappers from OvPhysxManager. Point unit tests at the in-memory _serialize_selected_stage path used by production warmup.
Treat create_geometry_mapping's None identity result as a valid cached value via an explicit ready flag, so mapped-offset and batch metadata are not rebuilt every frame for the common identity layout.
Require a separate visual Mesh prim before barycentric remapping instead of comparing vertex counts, so equal-count but non-identical visuals still drive cloth slots for Newton Warp and OVRTX.
Caching create_geometry_mapping's None identity result skipped the per-frame mapped-offset and batch-sync refresh that soft-body viz depends on, causing stretched or missing deformables in Franka soft rendering tests.
Use USD row-vector convention when baking discovered verts, clamp scatter copies to each destination slot so backend/shadow count mismatches cannot overwrite the next env, and invalidate discovery cache before PhysX/OVPhysX/shadow walks so cooked tet counts stay aligned.
Drop the process-global WeakKeyDictionary memo and invalidate helpers. Reuse discovery results via entries= instead; setup cost is unchanged.
fb7a5f5 to
b6c6918
Compare
|
@isaaclab-review-bot review |
There was a problem hiding this comment.
Isaac Lab Review Bot
The SceneData geometry contract and dual sim/visual shadow-particle design provide a coherent path for PhysX/OVPhysX deformables to drive Newton Warp and OVRTX. Before merge, the per-frame sync metadata churn should be removed, and wildcard-grouped deformables must not share barycentric remaps unless their topology is verified compatible.
- Design and architecture: Keeping SceneData simulation-true while the Newton shadow model owns visualization-sized render slots is a sound separation. However, grouping deformables solely by environment-wildcard paths assumes matching simulation and visual topology across environments; heterogeneous entries can consequently reuse incompatible remap tables and particle counts. Grouping must include topology characteristics or retain per-entry remaps.
- API: The additive SceneData points, geometry-path, and geometry-count interfaces have safe backend defaults and corresponding documentation and changelog coverage. The accepted concerns are internal implementation and grouping behavior rather than the public SceneData contract.
- Implementation: The discovery-to-render path correctly separates simulation and visualization buffers, but its hot path has avoidable costs: geometry scatter performs host synchronization, repeated metadata uploads, and a quadratic destination scan each frame, while identity mappings invalidate and rebuild batched remap/copy metadata every frame. Additionally, sharing a template remap across wildcard-grouped entries can produce invalid barycentric and tet indexing when their topologies differ.
Significant concerns. Posted 3 actionable findings inline.
Automated review; human maintainers own approval decisions.
| continue | ||
| # Space until the next destination slot (or end of buffer), not merely dest_size. | ||
| next_dest = dest_size | ||
| for offset in positive_dests: |
There was a problem hiding this comment.
🟡 Warning · Implementation — Per-frame host scan in points scatter
get_points calls this on every render frame, and each call performs mapping.numpy() (a device sync), a linear scan of positive_dests per entity (quadratic in deformable body count, i.e. envs × assets), and three fresh Warp uploads. Precompute the source/destination offset and count device arrays once and rebuild only when entity_counts or the mapping change; use bisect over the sorted offsets.
|
|
||
| # Invalidate the mapped-offset cache so that it can be rebuilt immediately after. | ||
| cls._mapped_sim_particle_offsets = None | ||
| cls._invalidate_shadow_deformable_batch_sync() |
There was a problem hiding this comment.
🟡 Warning · Implementation — Batch sync cache invalidated on identity mappings
Identity layouts make create_geometry_mapping return None, so _scene_data_geometry_mapping stays None and this block re-runs every render frame, calling _invalidate_shadow_deformable_batch_sync(). _ensure_shadow_deformable_batch_sync then rebuilds per-particle Python id lists and several Warp arrays every frame, defeating the sync_key cache it was added for. The sync_key comparison already detects real layout changes, so drop the unconditional invalidation here.
| register_usd_vis_point_bindings=uses_remap or template.sim_mesh_path == template.vis_mesh_path, | ||
| ) | ||
|
|
||
| group_volume_vis_remap = _build_volume_vis_remap(template, device) if uses_remap else None |
There was a problem hiding this comment.
🟡 Warning · Implementation — Shared remap assumes identical group topology
Wildcard groups are keyed only on env-rewritten root/sim/vis paths, then every member reuses the template's remap and entities[0].vis_particle_count. If two environments share prim names but differ in tet or visual vertex counts (heterogeneous multi-asset spawning), the batch kernel indexes bary_weights[local_vis] beyond the template rows and applies template tet indices to a different sim slice. Include per-entry vertex counts in the grouping key, or build a remap per entry.
daniela-hase
left a comment
There was a problem hiding this comment.
The Newton and Scene Data Provider changes seem good to me :)
…ombinations (isaac-sim#6773) # Description ## Context When **PhysX / OVPhysX** simulates and **Newton Warp / OVRTX** renders: | Role | Who owns it | What it looks like | |------|-------------|--------------------| | Simulation | PhysX / OVPhysX SceneData `get_points` | Soft-body **nodal** positions (tet nodes for volumes; surface verts for cloth) | | Visualization | Newton shadow `particle_q` and/or USD visual `Mesh.points` | Authored **visual** triangle mesh | ### Issues before this PR 1. **Warp “tet spaghetti”** — shadow model built from sim tet topology + live sim nodes → renderer draws tet surfaces, not the visual cuboid/cloth. See Before vs. After section. 2. **OVRTX static rest pose** — live sync broken → clean visual mesh but no motion/deformation. See Before vs. After section. ## Design goal Keep SceneData **sim-true** (nodal counts from physics), while consumers that render the authored mesh see **vis-sized** positions every frame — shared between Warp and OVRTX. ## Architecture ### Schema hierarchy on the USD stage Spawners (`define_deformable_body_properties`) and pre-authored USD share the same OmniPhysics layout. `OmniPhysicsDeformableBodyAPI` marks the **body root**; sim/vis meshes carry the **sim** and **pose** APIs. ``` Root Xform / Mesh OmniPhysicsDeformableBodyAPI ← body identity (discovery key) │ ├── SimulationMesh (TetMesh volume | Mesh surface; purpose=guide) │ OmniPhysicsVolumeDeformableSimAPI or OmniPhysicsSurfaceDeformableSimAPI │ UsdPhysics.CollisionAPI ← collider usually = sim mesh │ OmniPhysicsDeformablePoseAPI:default │ purposes = ["bindPose"] ← register pose for embedding │ └── VisualMesh (UsdGeom.Mesh; often different vertex count) OmniPhysicsDeformablePoseAPI:default purposes = ["bindPose"] points = authored vis rest verts ← skin/embed to sim via bindPose ``` | Schema | Where | Role | |--------|-------|------| | `OmniPhysicsDeformableBodyAPI` | body root | Marks the deformable; subtree deforms with it | | `OmniPhysics*DeformableSimAPI` | sim mesh | FEA topology / rest shape (volume tet or surface tri) | | `UsdPhysics.CollisionAPI` | sim mesh (typical) | Collision participation | | `OmniPhysicsDeformablePoseAPI` | sim **and** vis meshes | Multiple-apply bind pose so vis/collision can differ from sim | Optional third child (collision ≠ sim) also gets `CollisionAPI` + `DeformablePoseAPI:bindPose`. Isaac Lab spawners usually collide on the sim mesh. ### Pipeline (spawn → render) ``` ┌──────────────────────────────────────────────────────────────────────────┐ │ Spawners (meshes / from_files) — asset authoring │ │ create visual Mesh, then define_deformable_body_properties() │ │ → applies schema hierarchy above (Body / Sim / Pose / Collision) │ │ → authors sim TetMesh/Mesh (+ keeps sibling vis Mesh) │ │ (pre-authored USD may already have this setup and skip spawners) │ └───────────────────────────────┬──────────────────────────────────────────┘ | | | ▼ ┌──────────────────────────────────────────────────────────────────────────┐ │ USD stage (see schema hierarchy above) │ │ BodyAPI root → sim TetMesh/Mesh + vis sibling Mesh (V counts may differ)│ └───────────────────────────────┬──────────────────────────────────────────┘ | | ─────────────────────────────── │ ─ UNCHANGED above (authoring prerequisite) ─ | │ │ discover_deformables_on_stage() │ called by PhysxManager / OvPhysxManager / │ NewtonManager │ ┌─────────────────┴─────────────────┐ ▼ ▼ ┌─────────────────────────────┐ ┌──────────────────────────────────────────┐ │ PhysxManager / │ │ NewtonManager │ │ OvPhysxManager │ │ visualization_builder │ │ DeformableStageEntry → │ │ → add_shadow_deformables_to_builder │ │ SceneDataBackend points │ │ • volume + count mismatch → │ │ (sim-sized nodal export) │──▶│ VolumeVisRemap + add_cloth_mesh │ │ │ │ • volume 1:1 → add_soft_mesh │ │ │ │ • surface → add_cloth_mesh │ │ │ │ ShadowDeformableEntity (sim+vis slots) │ │ │ │ _sim_particle_q ← SceneData (sim-sized) │ │ │ │ particle_q ← remapped/copied (vis-sized)│ └─────────────────────────────┘ └───────────┬──────────────┬───────────────┘ │ │ ▼ ▼ Newton Warp renderer OVRTX (USD vis reads shadow Mesh.points ← particle_q particle_q slices) ``` **One-sentence summary:** managers discover sim/vis meshes; shadow build allocates dual particle layouts and (for volumes) a barycentric table; each frame PhysX/OVPhysX SceneData fills sim slots and a Warp kernel fills vis slots for renderers. ## Type of change - New feature (non-breaking change which adds functionality) - Documentation update ## Before vs. After ### Rendering | | Before | After | | -- | ------ | ----- | | “tet spaghetti” | <img width="262" height="262" alt="image" src="https://github.com/user-attachments/assets/3fcb22f2-076f-42ae-b3a4-3c2926ff41f8" /> | <img width="262" height="262" alt="ovphysx-newton_renderer-rgb" src="https://github.com/user-attachments/assets/82c6a44e-6a04-4a99-8f42-e42d3a7125da" /> | | Rendering Sync | <img width="262" height="262" alt="franka_cloth-ovphysx-ovrtx_renderer-rgb-before" src="https://github.com/user-attachments/assets/2148b565-66b7-4ba2-a1ed-4ce1d65a216b" /> | <img width="262" height="262" alt="franka_cloth-ovphysx-ovrtx_renderer-rgb-after" src="https://github.com/user-attachments/assets/f00ba2b5-9bb8-4333-92d5-cc44ffb395e4" /> | ### Total startup (s) (128 envs, 100 steps) | Task | Physics | Renderer | Before | After | Δ % | | :----------------------------- | :------ | :-------------- | -----: | ----: | ---: | | Isaac-Lift-Cloth-Franka-Camera | ovphysx | ovrtx | 81.4 | 93.0 | +14% | | Isaac-Lift-Cloth-Franka-Camera | ovphysx | newton_renderer | 75.0 | 90.6 | +21% | | Isaac-Lift-Soft-Franka-Camera | ovphysx | ovrtx | 77.0 | 81.4 | +6% | | Isaac-Lift-Soft-Franka-Camera | ovphysx | newton_renderer | 70.0 | 77.5 | +11% | ### Mean Total FPS (128 envs, 100 steps) | Task | Physics | Renderer | Before | After | Δ % | | :----------------------------- | :------ | :-------------- | -----: | ----: | ---: | | Isaac-Lift-Cloth-Franka-Camera | ovphysx | ovrtx | 1841 | 1574 | −15% | | Isaac-Lift-Cloth-Franka-Camera | ovphysx | newton_renderer | 5072 | 4575 | −10% | | Isaac-Lift-Soft-Franka-Camera | ovphysx | ovrtx | 1907 | 1601 | −16% | | Isaac-Lift-Soft-Franka-Camera | ovphysx | newton_renderer | 5766 | 5729 | −1% | ## Checklist - [x] I have read and understood the [contribution guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html) - [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with `./isaaclab.sh --format` - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] I have added a changelog fragment under `source/<pkg>/changelog.d/` for every touched package (do **not** edit `CHANGELOG.rst` or bump `extension.toml` — CI handles that) - [x] I have added my name to the `CONTRIBUTORS.md` or my name already exists there
# Description Revives #6308 on current `develop` and supersedes #3728 with a single backend-neutral contract for kinematic rigid-object rendering. ## Architecture `source/isaaclab/test/renderers/rigid_object_rendering_contract.py` is the composition root. It owns the cloned scene, kinematic pose sequence, depth measurements, and assertions. Package-local adapters own only availability checks, simulation/renderer selection, and backend cleanup: - Isaac RTX + PhysX on CPU and CUDA, with and without a coexisting articulation; - Newton Warp + PhysX on CUDA; - OVRTX + OVPhysX on CUDA through both legacy and OVStage scene ownership (OVStage runs when installed). The dependency direction is adapter -> shared test contract -> public Isaac Lab APIs. An AST architecture gate rejects backend imports in the shared contract and rejects scene, asset, sensor, or class ownership in adapters. The contract creates two cloned instanceable DexCubes with root-level nonuniform scale, verifies their depth silhouettes, moves both kinematic bodies through the public rigid-object tensor API, verifies the physics poses, and requires opposite rendered centroid displacement. ## Current-develop audit Most production changes in the old PR have since landed through newer ownership boundaries: Isaac RTX render-product lifetime in #6729, Newton shadow-state copying in #6773, OVRTX scale-aware transform writes in #7010, and Newton Fabric scale preservation in #7481. This revival removes those stale patches rather than carrying duplicate implementations. The revived contract exposed one remaining OVRTX bug: composed scale was captured only for clone-plan source paths, while OVRTX creates non-source destinations after exporting the host USD stage. Those destinations therefore defaulted to unit scale. As a deliberately temporary bridge, this PR projects only captured non-unit scales through the existing `isaaclab.cloner.query.path_env_ids` and `path_to_clone` boundary using the already-validated `ClonePlan`; real destination scales take precedence. It adds no plan fields, query APIs, renderer configuration, or per-body fallback, and the bridge can be deleted as one unit when SDP supplies composed scale aligned with canonical rigid-body paths. Historical context: [Isaac Sim forum report](https://forums.developer.nvidia.com/t/rigidbody-prim-is-not-updated-in-rendering-pipeline-if-set-to-kinematic/346608). ## Type of change - Bug fix - Shared regression coverage ## Testing - Isaac RTX contract: 4 passed (CUDA/CPU x articulation absent/present). - Newton Warp contract: 1 passed. - OVRTX contract: 2 passed (legacy and OVStage). - OVRTX renderer unit surface: 167 passed. - Core architecture and Newton visualization suites: 25 passed. - OVRTX clone-plan suite: 17 passed. - Cloner query and rendering-contract architecture suites: 87 passed. - Controlled OVRTX regression: failed before the production fix with clone silhouettes of 264 vs. 36 pixels; passed after the fix. - Incoming #7462 NumPy-backed `ClonePlan` query-boundary smoke check: passed unchanged, including non-dense environment ids. - `uv run isaaclab -f`: all hooks passed against the exact upstream `develop` base, including changelog validation. ## Checklist - [x] I have read and understood the contribution guidelines - [x] I have run the pre-commit checks - [x] Documentation changes are not applicable - [x] I have added unit and integration regression coverage - [x] I have added changelog fragments for every touched package - [x] My name is already present in `CONTRIBUTORS.md`
#7587) # Description Backports #6308 to `release/3.0.0`. The canonical merged commit `ab34e8c5e3ee7a2c5f260d1511714e5be3bed3eb` was cherry-picked with `-x` provenance. Eleven of its twelve source paths replay exactly. `source/isaaclab_ov/isaaclab_ov/renderers/ovrtx_renderer.py` required a localized release-compatible conflict resolution, so this PR is intentionally a draft for release-maintainer review. | Field | Commit | |---|---| | Original merged change | `ab34e8c5e3ee7a2c5f260d1511714e5be3bed3eb` | | Release base used | `1c754876008f0806fdcfda8e3a6b2f593b34d6fc` | | Proposed backport | `740e3d7b2efe15c5a25f671583d29c034602e36f` | ## Conflict resolution The release renderer already contains the prerequisite work from #6729, #6773, #7010, and #7481, but differs from the source parent around clone-plan handling and method documentation. The resolution preserves the release branch's tensor-backed `ClonePlan` validation and existing renderer structure, then adds only #6308's semantic change: - imports the existing `isaaclab.cloner.query` API; - passes the validated release clone plan into `_capture_object_scales`; - projects captured non-unit source scales to active clone destinations with `path_env_ids` and `path_to_clone`; - retains real destination scales via `setdefault`. No paths outside the original PR are changed. ## Type of change - Bug fix - Shared regression coverage ## Validation - Repository backport candidate validation passed across all 12 original source paths. - Per-file stable patch IDs match on 11 paths; only the conflict-resolved renderer path differs. - Shared rendering-contract architecture tests — 2 passed. - Focused clone-query tests for `path_env_ids` and `path_to_clone` — 4 passed. - Python compilation passed for all changed Python files. - All changed-file pre-commit hooks passed, including changelog and Git LFS checks. - `git diff --check upstream/release/3.0.0...HEAD` passed. - The focused OVRTX runtime test was retried with the documented `ov` extra, but the release lock has no macOS/arm64 environment. Backend rendering tests and the canonical `uv run isaaclab -f` remain pending Linux CI. ## Checklist - [x] I have read and understood the contribution guidelines - [x] I have run the available pre-commit checks - [x] Documentation changes are not applicable - [x] The original unit and integration regression coverage is preserved - [x] Changelog fragments are preserved for every touched package - [x] The original contributor is already listed in `CONTRIBUTORS.md` Co-authored-by: ooctipus <zhengyuz@nvidia.com>
Description
Context
When PhysX / OVPhysX simulates and Newton Warp / OVRTX renders:
get_pointsparticle_qand/or USD visualMesh.pointsIssues before this PR
Design goal
Keep SceneData sim-true (nodal counts from physics), while consumers that render the authored mesh see vis-sized positions every frame — shared between Warp and OVRTX.
Architecture
Schema hierarchy on the USD stage
Spawners (
define_deformable_body_properties) and pre-authored USD share the same OmniPhysics layout.OmniPhysicsDeformableBodyAPImarks the body root; sim/vis meshes carry the sim and pose APIs.OmniPhysicsDeformableBodyAPIOmniPhysics*DeformableSimAPIUsdPhysics.CollisionAPIOmniPhysicsDeformablePoseAPIOptional third child (collision ≠ sim) also gets
CollisionAPI+DeformablePoseAPI:bindPose. Isaac Lab spawners usually collide on the sim mesh.Pipeline (spawn → render)
One-sentence summary: managers discover sim/vis meshes; shadow build allocates dual particle layouts and (for volumes) a barycentric table; each frame PhysX/OVPhysX SceneData fills sim slots and a Warp kernel fills vis slots for renderers.
Type of change
Before vs. After
Rendering
Total startup (s)
(128 envs, 100 steps)
Mean Total FPS
(128 envs, 100 steps)
Checklist
pre-commitchecks with./isaaclab.sh --formatsource/<pkg>/changelog.d/for every touched package (do not editCHANGELOG.rstor bumpextension.toml— CI handles that)CONTRIBUTORS.mdor my name already exists there