Add shared kinematic rigid-object renderer contract - #6308
Conversation
| return silhouette_heights, silhouette_widths, centroids_x | ||
|
|
||
|
|
||
| def _write_pose_and_render(sim, rigid_object: RigidObject, camera: Camera, root_poses: torch.Tensor) -> torch.Tensor: | ||
| """Write a rigid-object pose, advance one frame, and return rendered depth.""" | ||
| rigid_object.write_root_pose_to_sim_index(root_pose=root_poses) | ||
| sim.step() | ||
| rigid_object.update(sim.cfg.dt) | ||
| camera.update(sim.cfg.dt) | ||
| torch.testing.assert_close( | ||
| rigid_object.data.root_link_pose_w.torch, | ||
| root_poses, | ||
| rtol=0.0, | ||
| atol=1.0e-4, | ||
| ) | ||
| return camera.data.output["distance_to_image_plane"].torch.clone() |
There was a problem hiding this comment.
Missing type annotation for
sim parameter
The _write_pose_and_render helper is missing a type hint for sim, while rigid_object, camera, and root_poses are all annotated. Downstream tools (e.g. mypy, pyright) and any future callers have no signal about what concrete type is expected — a stale usage passing the wrong context won't be caught statically.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| ) | ||
| ) | ||
| return rigid_object, articulation, camera | ||
|
|
||
|
|
||
| def _measure_depth_mask(depth: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: | ||
| """Return the silhouette height, width, and horizontal centroid for each camera.""" | ||
| valid = torch.isfinite(depth[..., 0]) & (depth[..., 0] < _MAX_OBJECT_DEPTH) | ||
| pixel_counts = valid.sum(dim=(1, 2)) | ||
| assert torch.all(pixel_counts >= _MIN_OBJECT_PIXELS), ( | ||
| f"Expected at least {_MIN_OBJECT_PIXELS} object pixels per camera, got {pixel_counts.tolist()}." | ||
| ) | ||
|
|
||
| silhouette_heights = valid.any(dim=2).sum(dim=1) | ||
| silhouette_widths = valid.any(dim=1).sum(dim=1) | ||
| image_x = torch.arange(depth.shape[2], device=depth.device, dtype=torch.float32) |
There was a problem hiding this comment.
Bare
assert in non-test helper function may lose context on failure
_measure_depth_mask is a plain function (not a test), so pytest's assertion introspection / rewriting doesn't apply when it is called from within _write_pose_and_render (which is itself also a plain helper). If pixel_counts fails the minimum-pixel guard, the only output is the f-string message — there's no captured locals, diff view, or surrounding context that pytest normally provides for assertions in test bodies. Consider using pytest.fail or raising a descriptive AssertionError explicitly, or annotating the function with inline comments explaining that assertion rewriting applies only to direct test-function bodies.
# Description Since #6314 landed, `test-isaaclab-ov` and `test-rendering-correctness-kitless` are silently skipped on every fork PR: the job-level `if:` conditions require a same-repository PR (or `develop`) whenever `ovphysx_wheelhouse_resource` is configured — which it now always is. Fork contributors and team members working from forks have had zero OVRTX / kitless rendering CI coverage since then, with no visible signal (the jobs just show "skipped"). The NGC trust boundary is correct (the wheelhouse download needs `NGC_API_KEY`, which fork PRs cannot access), and this PR keeps it intact — the `USE_OVPHYSX_WHEELHOUSE` env var from #6314 already resolves trust per run, and the NGC download step is gated on `wheelhouse-resource != ''`, so it never executes without credentials. This PR's own CI (it is a fork PR, and PR runs use the merge-commit workflow, so it exercises its own fix) established exactly which coverage is recoverable on the public pip stack: - **All `isaaclab_ov` (ovrtx) tests pass** with pip-index `ovrtx` + `ovphysx` — 0 failures. - **All 562 `isaaclab_ovphysx` test failures are one error**: `AttributeError: type object 'PhysX' has no attribute 'set_cpu_mode'` — `ovphysx_manager` now requires ovphysx ≥ 0.5.1, which only exists in the NGC wheelhouse; the newest public wheel is 0.4.13. ovrtx does not depend on ovphysx, so the fallback separates them at the finest granularity each job allows: - `test-isaaclab-ov` **runs on fork PRs** via the pip fallback with `exclude-pattern: isaaclab_ovphysx` (file-level — the two packages live in separate test trees; the shared `filter-pattern: "isaaclab_ov"` only bundles them by prefix match). - `test-rendering-correctness-kitless` **runs on fork PRs** with a new `test-k-expr` input that reaches the per-file pytest subprocesses spawned by `tools/conftest.py` (param-level: `not ovphysx` — the golden-image files parametrize physics backends inside each file, so fork runs keep the `newton + ovrtx` combinations and deselect only the ovphysx-backed params). - Trusted runs (same-repo PRs to `develop`, post-merge `develop`) are byte-for-byte unchanged. Once ovphysx ≥ 0.5.1 is published to the public pip index, the exclude and the `-k` deselect can both be dropped and fork PRs regain full parity. cc @AntoineRichard — #6314's description says "Do not merge; this PR exists only for CI validation", so flagging in case the fork-PR skip wasn't meant to reach `develop` in this form at all. Fixes the coverage gap observed on #6308, where the OVRTX-variant jobs skip on every attempt. ## Type of change - Bug fix (non-breaking change which fixes an issue) ## 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` - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have updated the changelog and the corresponding version in the extension's `config/extension.toml` file - [x] I have added my name to the `CONTRIBUTORS.md` or my name already exists there
…m#6348) # Description Since isaac-sim#6314 landed, `test-isaaclab-ov` and `test-rendering-correctness-kitless` are silently skipped on every fork PR: the job-level `if:` conditions require a same-repository PR (or `develop`) whenever `ovphysx_wheelhouse_resource` is configured — which it now always is. Fork contributors and team members working from forks have had zero OVRTX / kitless rendering CI coverage since then, with no visible signal (the jobs just show "skipped"). The NGC trust boundary is correct (the wheelhouse download needs `NGC_API_KEY`, which fork PRs cannot access), and this PR keeps it intact — the `USE_OVPHYSX_WHEELHOUSE` env var from isaac-sim#6314 already resolves trust per run, and the NGC download step is gated on `wheelhouse-resource != ''`, so it never executes without credentials. This PR's own CI (it is a fork PR, and PR runs use the merge-commit workflow, so it exercises its own fix) established exactly which coverage is recoverable on the public pip stack: - **All `isaaclab_ov` (ovrtx) tests pass** with pip-index `ovrtx` + `ovphysx` — 0 failures. - **All 562 `isaaclab_ovphysx` test failures are one error**: `AttributeError: type object 'PhysX' has no attribute 'set_cpu_mode'` — `ovphysx_manager` now requires ovphysx ≥ 0.5.1, which only exists in the NGC wheelhouse; the newest public wheel is 0.4.13. ovrtx does not depend on ovphysx, so the fallback separates them at the finest granularity each job allows: - `test-isaaclab-ov` **runs on fork PRs** via the pip fallback with `exclude-pattern: isaaclab_ovphysx` (file-level — the two packages live in separate test trees; the shared `filter-pattern: "isaaclab_ov"` only bundles them by prefix match). - `test-rendering-correctness-kitless` **runs on fork PRs** with a new `test-k-expr` input that reaches the per-file pytest subprocesses spawned by `tools/conftest.py` (param-level: `not ovphysx` — the golden-image files parametrize physics backends inside each file, so fork runs keep the `newton + ovrtx` combinations and deselect only the ovphysx-backed params). - Trusted runs (same-repo PRs to `develop`, post-merge `develop`) are byte-for-byte unchanged. Once ovphysx ≥ 0.5.1 is published to the public pip index, the exclude and the `-k` deselect can both be dropped and fork PRs regain full parity. cc @AntoineRichard — isaac-sim#6314's description says "Do not merge; this PR exists only for CI validation", so flagging in case the fork-PR skip wasn't meant to reach `develop` in this form at all. Fixes the coverage gap observed on isaac-sim#6308, where the OVRTX-variant jobs skip on every attempt. ## Type of change - Bug fix (non-breaking change which fixes an issue) ## 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` - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have updated the changelog and the corresponding version in the extension's `config/extension.toml` file - [x] I have added my name to the `CONTRIBUTORS.md` or my name already exists there
d7577df to
0174e13
Compare
|
run-ci |
|
I would make #6308 a deliberately temporary, deletable bridge—using today’s ClonePlan without adding any new plan fields or APIs. Use the existing query boundary and pass the already-required plan explicitly: from isaaclab.cloner import ClonePlan def _capture_object_scales(self, stage: Any, plan: ClonePlan) -> None: Call it only after prepare_stage() has validated the plan: self._capture_object_scales(stage, self._clone_plan) Why this transition is clean:
I would not resolve every object path through path_to_source() inside _create_object_scale_array(). Although visually flatter, it queries every rigid body in every environment. A host-only 4,096×48-body check cost roughly one second, including completely unscaled bodies. Source-side For testing, keep the cross-backend rendered contract. Change the focused OVRTX unit test to assert the resulting scale array for source and destination bodies, rather than asserting the private dictionary’s exact contents. That lets the temporary cache disappear later without The later SDP cutover should replace the whole bridge: Plan completion: exact rigid-body paths + composed scales Importantly, future FrameLayout.scale currently records only local xformOp:scale; the final conversion needs composed scale aligned with the canonical rigid-body paths. Once that exists, delete _capture_object_scales, _object_scales_by_path, and the destination projection together. That version can merge before or after #7462 and should transition without another mechanical rewrite. |
|
run-ci |
|
run-ci |
# Description Restores the missing `torch` import in `test_ovrtx_clone_plan.py`. #7462 converted the existing clone-plan test inputs from Torch tensors to NumPy arrays and removed the then-unused import. #6308 subsequently added a new object-scale test using `torch.ones` and `torch.arange` without restoring the import, causing the repository-wide Ruff pre-commit check to fail with `F821 Undefined name torch`. This PR contains only the import repair and an `isaaclab_ov` `.skip` changelog fragment. It unblocks #7579 and other changes based on the current `develop` branch. ## Type of change - Bug fix (non-breaking test fix) ## Release backport - [ ] <!-- backport-active-release --> Backport this pull request to the active release branch after it merges into `develop` No release backport is required: `release/3.0.0` already imports `torch` in this test. ## Screenshots Not applicable. ## Testing - `uv run --no-project --with pre-commit python -m pre_commit run --all-files` - `uv run --no-project python tools/changelog/cli.py check --include-worktree` - `git diff --check upstream/develop...HEAD` ## Checklist - [x] I have read and understood the contribution guidelines - [x] I have run the full pre-commit checks - [x] Documentation changes are not required because no public API changed - [x] My changes generate no new warnings - [x] The fix directly covers the Ruff `F821` failure - [x] I have added an `isaaclab_ov` changelog fragment - [x] My name already exists 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
Revives #6308 on current
developand supersedes #3728 with a single backend-neutral contract for kinematic rigid-object rendering.Architecture
source/isaaclab/test/renderers/rigid_object_rendering_contract.pyis 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: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_idsandpath_to_cloneboundary using the already-validatedClonePlan; 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.
Type of change
Testing
ClonePlanquery-boundary smoke check: passed unchanged, including non-dense environment ids.uv run isaaclab -f: all hooks passed against the exact upstreamdevelopbase, including changelog validation.Checklist
CONTRIBUTORS.md