-
Notifications
You must be signed in to change notification settings - Fork 619
Honor selfCollisionEnabled on imported cables #3709
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -12,12 +12,15 @@ | |||||||||||||
|
|
||||||||||||||
| from __future__ import annotations | ||||||||||||||
|
|
||||||||||||||
| import itertools | ||||||||||||||
| import math | ||||||||||||||
| import warnings | ||||||||||||||
| from dataclasses import replace | ||||||||||||||
| from typing import TYPE_CHECKING | ||||||||||||||
|
|
||||||||||||||
| import warp as wp | ||||||||||||||
|
|
||||||||||||||
| from ..usd.schema_resolver import PrimType | ||||||||||||||
| from .import_usd_deformable_utils import ( | ||||||||||||||
| _DEFAULT_CABLE_RADIUS, | ||||||||||||||
| _apply_cable_masses, | ||||||||||||||
|
|
@@ -40,6 +43,22 @@ | |||||||||||||
| _warn_unsupported_rest_fields, | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| if TYPE_CHECKING: | ||||||||||||||
| from ..sim.builder import ModelBuilder | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| def _filter_cable_self_collisions(builder: ModelBuilder, bodies: list[int]) -> None: | ||||||||||||||
| """Filter every shape pair among a cable articulation's bodies to disable self-collision. | ||||||||||||||
|
|
||||||||||||||
| Like the rigid importer's self-collision filtering, this emits every body pair, including | ||||||||||||||
| the adjacent ones the CABLE joints already filter (``collision_filter_parent``); the | ||||||||||||||
| duplicates are deduplicated when the filter pairs are consumed. | ||||||||||||||
| """ | ||||||||||||||
| for b1, b2 in itertools.combinations(bodies, 2): | ||||||||||||||
| for s1 in builder.body_shapes[b1]: | ||||||||||||||
| for s2 in builder.body_shapes[b2]: | ||||||||||||||
| builder.add_shape_collision_filter_pair(s1, s2) | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| def _read_validated_curve_topology(curves, path: str, *, warn: bool = True): | ||||||||||||||
| """Read a cable prim's ``points`` / ``curveVertexCounts`` after validating the partition. | ||||||||||||||
|
|
@@ -418,6 +437,34 @@ def global_node(local: tuple[str, int]) -> int: | |||||||||||||
| body_frame_origin="com", | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| # Resolve self-collision only for a colliding graph; for the welded-graph policy see | ||||||||||||||
| # docs/concepts/usd_parsing.rst. get_value_with_resolver returns resolver=None for an | ||||||||||||||
| # unauthored curve (it stays neutral); the default= below does not feed the result, it | ||||||||||||||
| # only suppresses the unresolved-value diagnostic, so do not drop it as dead code. | ||||||||||||||
| if collision_enabled: | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 Could you collect all active resolver attributes for each accepted cable prim before this collision check?
Suggested change
A regression test with both Newton and PhysX resolvers, plus a non-colliding welded graph, would help pin this down. |
||||||||||||||
| authored_self_collisions: list[bool] = [] | ||||||||||||||
| for key in comp_paths: | ||||||||||||||
| value, resolver = ctx.resolver.get_value_with_resolver( | ||||||||||||||
| curve_recs[key].prim, | ||||||||||||||
| prim_type=PrimType.ARTICULATION, | ||||||||||||||
| key="self_collision_enabled", | ||||||||||||||
| default=ctx.enable_self_collisions, | ||||||||||||||
| verbose=verbose, | ||||||||||||||
| ) | ||||||||||||||
| if resolver is not None: | ||||||||||||||
| authored_self_collisions.append(bool(value)) | ||||||||||||||
| graph_self_collision = ( | ||||||||||||||
| all(authored_self_collisions) if authored_self_collisions else ctx.enable_self_collisions | ||||||||||||||
| ) | ||||||||||||||
| if len(set(authored_self_collisions)) > 1: | ||||||||||||||
| warnings.warn( | ||||||||||||||
| f"cable graph '{cid}': welded cables mix self-collision-enabled and " | ||||||||||||||
| f"self-collision-disabled curves; the whole graph disables self-collision.", | ||||||||||||||
| stacklevel=2, | ||||||||||||||
| ) | ||||||||||||||
| if not graph_self_collision: | ||||||||||||||
| _filter_cable_self_collisions(builder, body_ids) | ||||||||||||||
|
|
||||||||||||||
| # Partition graph bodies back to their owning curve, and rebuild the per-prim anchor | ||||||||||||||
| # maps the curve-to-xform attachment pass reads (point index / segment index -> body). | ||||||||||||||
| per_prim_segments: dict[str, dict[int, tuple[int, float]]] = {} | ||||||||||||||
|
|
@@ -627,6 +674,17 @@ def _deformable_import_cable(ctx: _DeformableImportContext, consumed_cable_curve | |||||||||||||
| has_shape_collision=collision_enabled, | ||||||||||||||
| has_particle_collision=collision_enabled, | ||||||||||||||
| ) | ||||||||||||||
| # Each curve in this prim becomes its own articulation via add_rod below, so resolve the | ||||||||||||||
| # prim's self-collision flag once and apply the filter per curve (not across sibling curves). | ||||||||||||||
| self_collision_enabled = bool( | ||||||||||||||
| ctx.resolver.get_value( | ||||||||||||||
| prim, | ||||||||||||||
| prim_type=PrimType.ARTICULATION, | ||||||||||||||
| key="self_collision_enabled", | ||||||||||||||
| default=ctx.enable_self_collisions, | ||||||||||||||
| verbose=verbose, | ||||||||||||||
| ) | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| cable_bodies: list[int] = [] | ||||||||||||||
| cable_joints: list[int] = [] | ||||||||||||||
|
|
@@ -719,6 +777,8 @@ def _deformable_import_cable(ctx: _DeformableImportContext, consumed_cable_curve | |||||||||||||
| wrap_in_articulation=True, | ||||||||||||||
| body_frame_origin="com", | ||||||||||||||
| ) | ||||||||||||||
| if collision_enabled and not self_collision_enabled: | ||||||||||||||
| _filter_cable_self_collisions(builder, bodies) | ||||||||||||||
| cable_bodies.extend(bodies) | ||||||||||||||
| cable_joints.extend(joints) | ||||||||||||||
| cable_point_runs.append((start, n, bodies)) | ||||||||||||||
|
|
||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.