Mesh and Heightfield collision support for Kamino#2280
Mesh and Heightfield collision support for Kamino#2280nvtw merged 16 commits intonewton-physics:mainfrom
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds GeoType properties for primitive/explicit classification; threads per-shape mesh/heightfield and collision buffers through Kamino (model, builder, pipeline); implements HFieldShape; switches checks to use Changes
Sequence Diagram(s)sequenceDiagram
participant NewtonModel as Newton Model
participant ModelConv as ModelKamino.from_newton
participant Pipeline as CollisionPipelineUnifiedKamino
participant NarrowPhase as Narrow-phase Backend
participant NewtonCD as Newton Collision (newton.collide)
participant Converter as convert_contacts_newton_to_kamino
participant KaminoSolver as Kamino Solver
NewtonModel->>ModelConv: emit shape arrays (types, mesh/hfield buffers, AABBs, radii)
ModelConv->>Pipeline: build GeometriesModel (includes collision/heightfield fields)
Pipeline->>Pipeline: scan types -> set _has_explicit
alt _has_explicit == true
Pipeline->>NarrowPhase: provide collision_aabb_*/voxel_resolution/heightfield_* buffers
NewtonCD->>Converter: (when using Newton collisions) produce contacts
Converter->>KaminoSolver: convert to ContactsKamino
else
Pipeline->>NarrowPhase: provide placeholders for explicit inputs
end
KaminoSolver->>NarrowPhase: launch narrow-phase with collision_radius array
NarrowPhase->>KaminoSolver: return contacts
Estimated code review effort🎯 4 (Complex) | ⏱️ ~55 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
newton/_src/solvers/kamino/_src/core/shapes.py (1)
626-699:⚠️ Potential issue | 🟠 MajorPrimitive–heightfield pairs can still allocate zero contact capacity.
The new
GeoType.HFIELDhandling only exists in thetype_a == GeoType.HFIELDand mesh/convex branches. After the canonical sort, any primitive/heightfield pair that still enters one of the earlier primitive branches has notype_b == GeoType.HFIELDcase and falls through to(0, 0).newton/_src/solvers/kamino/_src/core/conversions.py:235-260uses this return value to sizeworld_max_contacts, so the defaultModelKamino.from_newton()path can still under-allocate and drop real contacts.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@newton/_src/solvers/kamino/_src/core/shapes.py` around lines 626 - 699, The function that returns contact capacity for (type_a, type_b) can return (0,0) for primitive vs HFIELD because only the final HFIELD and mesh branches handle HFIELD; to fix, ensure any branch handling a primitive also checks for type_b == GeoType.HFIELD and returns the conservative capacity (e.g. _MESH_CONVEX_MAX, 0), or perform a canonical swap early so GeoType.HFIELD is always handled by the dedicated HFIELD branch; update the primitive branches (cases for GeoType.SPHERE/CAPSULE/ELLIPSOID/CYLINDER/BOX and the mesh/convex branch) to explicitly handle type_b == GeoType.HFIELD (returning _MESH_CONVEX_MAX, 0) so ModelKamino.from_newton and conversions.py sizing no longer under-allocates.
🧹 Nitpick comments (1)
newton/_src/solvers/kamino/_src/core/model.py (1)
1324-1331: The private field coupling is safe and does not require fixes.
_shape_voxel_resolutionis properly initialized duringModel.finalize()in a loop that populates the array for all shapes, and it is always device-backed viawp.array(..., device=device). The field is guaranteed to be set before Kamino'sfrom_newton()consumes it. While exposing a public accessor would reduce coupling, the current approach is functionally sound.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@newton/_src/solvers/kamino/_src/core/model.py` around lines 1324 - 1331, No functional change required because Model.finalize() populates model._shape_voxel_resolution before Kamino.from_newton() consumes it; if you want a safety improvement, either add a short assertion at the start of Kamino.from_newton() verifying model._shape_voxel_resolution is set and device-backed (to fail fast with a clear message), or add a public accessor property on Model (e.g., Model.shape_voxel_resolution) that returns the wp.array and use that in from_newton() instead of the private attribute.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@newton/_src/solvers/kamino/examples/rl/example_rl_bipedal.py`:
- Around line 169-171: The _make_balls_fn function currently slices
BALL_POSITIONS with num_balls without validation leading to negative or
too-large inputs producing unexpected results; before using num_balls in the
slice, validate and clamp it to a safe range (e.g., clamp num_balls = max(0,
min(num_balls, min(5, len(BALL_POSITIONS)))) or alternatively raise a ValueError
for out-of-range values), and update any doc/help text if you change behavior so
callers know the enforced max; refer to the _make_balls_fn function and the
BALL_POSITIONS constant when making the change.
In `@newton/_src/solvers/kamino/examples/rl/simulation.py`:
- Around line 82-89: The single-world path can leave negative shape_world (wid
== -1) entries in Newton contact data which later feed
convert_contacts_newton_to_kamino; to fix, when use_newton_collisions is true
and newton_model.world_count == 1, sanitize the Newton contact/shape_world data
by replacing negative shape_world/wid values with 0 on the model/state/contacts
you store (referencing newton_model, self._newton_state, self._newton_contacts
and the converter convert_contacts_newton_to_kamino) before any conversion or
use — i.e., after assigning self._newton_state/self._newton_contacts (and before
creating ContactsKamino or calling convert_contacts_newton_to_kamino) iterate
the contact shape_world/wid entries and set negative values to 0.
- Around line 82-89: The Newton-CD branch currently sizes ContactsKamino using
newton_model.rigid_contact_max and ignores the configured cap, so update the
allocation logic in the use_newton_collisions branch (where self._newton_model,
self._newton_state, self._newton_contacts are set and per_world/world_max are
computed) to clamp per_world by the configured max_contacts_per_world (e.g.,
config.collision_detector.max_contacts_per_world or the corresponding variable
passed into the module) before building world_max and calling
ContactsKamino(capacity=world_max, ...); ensure the clamp applies per-world (use
min(rigid_contact_max-derived value, max_contacts_per_world)) so the configured
cap is honored for heightfield/mesh scenes that force
use_newton_collisions=True.
---
Outside diff comments:
In `@newton/_src/solvers/kamino/_src/core/shapes.py`:
- Around line 626-699: The function that returns contact capacity for (type_a,
type_b) can return (0,0) for primitive vs HFIELD because only the final HFIELD
and mesh branches handle HFIELD; to fix, ensure any branch handling a primitive
also checks for type_b == GeoType.HFIELD and returns the conservative capacity
(e.g. _MESH_CONVEX_MAX, 0), or perform a canonical swap early so GeoType.HFIELD
is always handled by the dedicated HFIELD branch; update the primitive branches
(cases for GeoType.SPHERE/CAPSULE/ELLIPSOID/CYLINDER/BOX and the mesh/convex
branch) to explicitly handle type_b == GeoType.HFIELD (returning
_MESH_CONVEX_MAX, 0) so ModelKamino.from_newton and conversions.py sizing no
longer under-allocates.
---
Nitpick comments:
In `@newton/_src/solvers/kamino/_src/core/model.py`:
- Around line 1324-1331: No functional change required because Model.finalize()
populates model._shape_voxel_resolution before Kamino.from_newton() consumes it;
if you want a safety improvement, either add a short assertion at the start of
Kamino.from_newton() verifying model._shape_voxel_resolution is set and
device-backed (to fail fast with a clear message), or add a public accessor
property on Model (e.g., Model.shape_voxel_resolution) that returns the wp.array
and use that in from_newton() instead of the private attribute.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: a9b75da9-ce53-4444-b594-7510aa768ef6
📒 Files selected for processing (9)
newton/_src/geometry/types.pynewton/_src/solvers/kamino/_src/core/builder.pynewton/_src/solvers/kamino/_src/core/geometry.pynewton/_src/solvers/kamino/_src/core/model.pynewton/_src/solvers/kamino/_src/core/shapes.pynewton/_src/solvers/kamino/_src/geometry/unified.pynewton/_src/solvers/kamino/examples/rl/example_rl_bipedal.pynewton/_src/solvers/kamino/examples/rl/simulation.pynewton/_src/solvers/kamino/tests/test_geometry_mesh_heightfield.py
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
newton/_src/solvers/kamino/examples/rl/simulation.py (1)
862-863:⚠️ Potential issue | 🟡 MinorDocstring inconsistency:
q_j_refclaimsnum_joint_coordsbut is shaped tonum_joint_dofs.The docstring says
(num_worlds, num_joint_coords)but line 447 reshapes to(nw, njd)(DOF space), which is correct for PD position targets. The docstring should saynum_joint_dofs.📝 Proposed fix
`@property` def q_j_ref(self) -> torch.Tensor: - """Joint position reference ``(num_worlds, num_joint_coords)`` for implicit PD.""" + """Joint position reference ``(num_worlds, num_joint_dofs)`` for implicit PD.""" return self._q_j_ref🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@newton/_src/solvers/kamino/examples/rl/simulation.py` around lines 862 - 863, The docstring for the q_j_ref property incorrectly says "num_joint_coords" while the stored shape is (nw, njd) in DOF space; update the q_j_ref docstring to state "(num_worlds, num_joint_dofs)" (or use "num_joint_dofs" consistently) to match the actual reshape and the attribute _q_j_ref so callers understand this is DOF-space joint position references.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@newton/_src/solvers/kamino/examples/rl/simulation.py`:
- Around line 862-863: The docstring for the q_j_ref property incorrectly says
"num_joint_coords" while the stored shape is (nw, njd) in DOF space; update the
q_j_ref docstring to state "(num_worlds, num_joint_dofs)" (or use
"num_joint_dofs" consistently) to match the actual reshape and the attribute
_q_j_ref so callers understand this is DOF-space joint position references.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: a344b3df-189f-4690-a6fd-1533764b0858
📒 Files selected for processing (7)
newton/_src/geometry/types.pynewton/_src/solvers/kamino/_src/core/geometry.pynewton/_src/solvers/kamino/_src/core/model.pynewton/_src/solvers/kamino/_src/geometry/unified.pynewton/_src/solvers/kamino/examples/rl/example_rl_bipedal.pynewton/_src/solvers/kamino/examples/rl/simulation.pynewton/_src/solvers/kamino/tests/test_geometry_unified.py
✅ Files skipped from review due to trivial changes (1)
- newton/_src/solvers/kamino/tests/test_geometry_unified.py
🚧 Files skipped from review as they are similar to previous changes (2)
- newton/_src/solvers/kamino/_src/core/model.py
- newton/_src/solvers/kamino/examples/rl/example_rl_bipedal.py
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@newton/_src/solvers/kamino/_src/geometry/unified.py`:
- Around line 524-527: The current detection packs heightfields with meshes into
_has_explicit, causing NarrowPhase to be created with has_meshes=True even when
only heightfields exist; change the detection to compute two booleans: one (e.g.
_has_meshes) that checks for GeoType.MESH and GeoType.CONVEX_MESH, and another
(e.g. _has_heightfields) that checks for GeoType.HFIELD, then pass both
explicitly to NarrowPhase as has_meshes=_has_meshes and
has_heightfields=_has_heightfields so the mesh-mesh contact kernel is
enabled/disabled correctly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: d135857f-b5e9-4700-9b2a-7cad58dbe69e
📒 Files selected for processing (1)
newton/_src/solvers/kamino/_src/geometry/unified.py
vastsoun
left a comment
There was a problem hiding this comment.
Code looks good, but I get SIGSEGV when running the unit tests on this branch. It seems to be the new Mesh + Heighfield UTs
This should be addressed now |
|
Code looks good to me, just the following tests seem to fail:
|
Indeed, should be fixed now |
Description
Mesh and Heightfield collision support for Kamino
Checklist
CHANGELOG.mdhas been updated (if user-facing change)Test plan
TODO - testing is currently not sufficient
Summary by CodeRabbit
New Features
Refactor
Tests