Hi,
I am using Isaac Sim 5.1 on Ubuntu 22.04.
I imported a custom 6-DOF robotic arm URDF as a referenced model.
The arm model is visible in the viewport. When I create a Cube and run the simulation, the Cube seems to collide with the robotic arm, so the arm appears to have working physical collision.
However, I cannot see the arm collision bodies.
I enabled collider visualization from the viewport:
Show by Type → Physics → Colliders
But I can only clearly see the GroundPlane collider. I do not see collision outlines or collision bodies for the robotic arm links.
I also ran a diagnostic script to list Mesh prims in the current Stage. It only finds the GroundPlane mesh:
```text
=== Mesh prims found ===
/World/GroundPlane/CollisionMesh
Total Mesh prims: 1
When I try to add collision to robot mesh prims, the script reports:
Done. Added collision to 0 mesh prims.
So the issue is not necessarily that the robotic arm has no collision. The issue is:
The 6-DOF arm seems to physically collide with a Cube, but I cannot visualize or inspect its collision bodies after importing the URDF as a referenced model.
Questions:
For a URDF imported as a referenced model, should the collision bodies be visible with Show by Type → Physics → Colliders?
If the Cube collides with the arm, does that mean the URDF collision was imported correctly?
Where are the collision bodies stored for a referenced URDF-imported robot?
Should I open the referenced USD asset directly to inspect or edit the collision bodies?
Why does Usd.PrimRange(stage.GetPseudoRoot()) only find the GroundPlane mesh and not the arm meshes?
What is the correct way to inspect collision shapes on a referenced 6-DOF arm in Isaac Sim 5.1?
This is a known issue with collider visualization for URDF models
imported as referenced models. Your collision data IS there (which
is why the Cube collides with the arm), but the viewport overlay
can’t render it due to how the URDF importer structures the output
USD.
Why this happens (5.1):
In Isaac Sim 5.1, the URDF importer routes collision data
(PhysicsCollisionAPI) to a separate sublayer (_physics.usd).
PhysX reads the fully composed stage and finds it correctly, but
the Show by Type -> Physics -> Colliders viewport overlay does
not traverse into the sublayer-within-reference composition.
Workaround for 5.1 – open the exported USD directly:
The most reliable way to see your colliders is to open the exported
robot USD file directly (File → Open the .usd file itself, not as
a reference in another stage). The wireframes will appear normally
when the robot USD is the root stage.
Status in 6.0:
Isaac Sim 6.0 restructures the URDF import pipeline. Collision data
no longer lives in a separate sublayer. However, the asset
transformer marks all geometry (including collision meshes) as instanceable = true for GPU instancing optimization. The viewport
collider overlay still can’t render wireframes because it uses
default prim traversal which skips instanced prims.
If you are on 6.0, there is a workaround: select the collision
geometry prims in the Stage tree and uncheck Instanceable in the
Property panel. The green collider wireframes will then appear.
(See also: Can't see colliders for a prior
report of this same issue with the same workaround.)
Why your script only finds GroundPlane:
Two issues:
Your script searches for Mesh type prims, but URDF collision
elements are often simple shapes (Cylinder, Sphere, Capsule).
Search for UsdPhysics.CollisionAPI instead of prim type.
For 6.0, Default Usd.PrimRange traversal skips instanced prims. Use Usd.TraverseInstanceProxies() to include them:
from pxr import Usd, UsdPhysics
import omni.usd
stage = omni.usd.get_context().get_stage()
for prim in Usd.PrimRange(stage.GetPseudoRoot(), Usd.TraverseInstanceProxies()):
if prim.HasAPI(UsdPhysics.CollisionAPI):
print(f"Collision: {prim.GetPath()} [{prim.GetTypeName()}]")
Thanks. I tried the suggested workaround: I opened the exported robot USD directly with File → Open, not as a reference in another parent stage.
However, the robot collision bodies are still not visible with:
Show by Type → Physics → Colliders
I also tried checking the composed stage with `Usd.TraverseInstanceProxies()` and confirmed that CollisionAPI exists on the arm links:
```text
/World/lebai_lm3_isaac/base_link/collisions/base_link/node_STL_BINARY_ | Xform
/World/lebai_lm3_isaac/link_1/collisions/link1/node_STL_BINARY_ | Xform
/World/lebai_lm3_isaac/link_2/collisions/link2/node_STL_BINARY_ | Xform
/World/lebai_lm3_isaac/link_3/collisions/link3/node_STL_BINARY_ | Xform
/World/lebai_lm3_isaac/link_4/collisions/link4/node_STL_BINARY_ | Xform
/World/lebai_lm3_isaac/link_5/collisions/link5/node_STL_BINARY_ | Xform
/World/lebai_lm3_isaac/link_6/collisions/link6/node_STL_BINARY_ | Xform
The Cube also collides with the arm, so collision seems active.
Does this mean the remaining issue is only collider debug visualization? Is there another recommended way in Isaac Sim 5.1 to visualize URDF-imported collision shapes when CollisionAPI is authored on Xform prims rather than Mesh prims?
Thanks for the follow-up — the prim paths you shared clarify the issue.
The CollisionAPI on your robot is applied to Xform prims
(node_STL_BINARY_), which have no renderable geometry. The collider
overlay draws wireframes based on the prim’s geometry, so an Xform
gives it nothing to draw — even when it finds the prim correctly.
This is a bug in the 5.1 URDF importer: when importing STL-based
collision elements, it wraps them in an Xform container and applies
CollisionAPI to the container instead of the child Mesh.
We checked the 6.0 importer and confirmed it places CollisionAPI
directly on Mesh prims, which is the correct behavior. If you’re able
to test with Isaac Sim 6.0 (dev2), the collider visualization should
work for your Lebai LM3 after re-importing the URDF.
If upgrading isn’t an option right now, you can try moving CollisionAPI
to the child Mesh prims on 5.1 as a workaround:
from pxr import Usd, UsdPhysics
import omni.usd
stage = omni.usd.get_context().get_stage ()
for prim in Usd.PrimRange(stage.GetPseudoRoo t()):
if prim.HasAPI(UsdPhysics.Collision API) and prim.GetTypeName() == "Xform":
for child in prim.GetChildren():
if child.GetTypeName() == "Mesh":
UsdPhysics.CollisionAPI.Apply(ch ild)
UsdPhysics.MeshCollisionAPI.Appl y(child)
print(f"Applied CollisionAPI to {child.GetPath()}")
After running this, toggle Show by Type → Physics → Colliders off and
on. The wireframes should appear on the mesh geometry.
but these mesh prims are instance proxy geometry prims, so the original script could not directly apply the APIs to them.
I created two modified test scripts and will attach both of them.
The first modified script finds the instanceable collision geometry roots and sets instanceable = false.
After running only the first modified script, the collider wireframes already became visible in the viewport. However, the wireframes are red.
The second modified script then tries to apply UsdPhysics.CollisionAPI and UsdPhysics.MeshCollisionAPI directly to the actual Mesh prims after disabling instanceable. I will attach this script as well, but the important observation is that the red wireframes already appeared after running the first modified script.
So the current result is:
Original provided code: applied to 0 mesh prims.
Modified script 1: disables instanceable on the collision geometry roots.
After modified script 1: collider wireframes become visible, but they are red.
Modified script 2: also attached for reference.
My questions are:Is red collider wireframe color expected in this case, or does it indicate an invalid collision setup?
Thanks for the detailed follow-up and for sharing your model and scripts.
Red wireframes are expected and correct. The viewport color-codes collider wireframes by collision type:
Green = convex hull approximation
Red = triangle mesh collision (MeshCollisionAPI)
Blue = SDF mesh collision
Your URDF uses STL-based collision geometry, which the importer brings in as triangle meshes. Red wireframes confirm your collision is working correctly — it’s just showing you the collision type, not an error.
About the workaround: You’re right that disabling instanceable alone is enough to make the wireframes appear. The reason is that the viewport collider overlay skips instanced subtrees during traversal, so clearing that flag is the key step.
However, there’s a subtlety worth noting: the CollisionAPI in your scene is currently applied to the Xform prim (node_STL_BINARY_) rather than the child Mesh prim. PhysX handles this fine (it traverses children to find geometry), but for full
correctness you can also apply the API to the Mesh. Here’s a cleaned-up two-phase script that does both:
from pxr import Usd, UsdPhysics
import omni.usd
stage = omni.usd.get_context().get_stage ()
# Phase 1: Disable instanceable on collision subtrees
to_unset = []
for prim in Usd.PrimRange(stage.GetPseudoRoo t()):
if prim.IsInstance() and "collisions" in str(prim.GetPath()):
to_unset.append(str(prim.GetPath ()))
for path_str in to_unset:
stage.GetPrimAtPath(path_str).Se tInstanceable(False)
print(f"Cleared instanceable: {path_str}")
# Phase 2: Apply CollisionAPI to child Mesh prims
for prim in Usd.PrimRange(stage.GetPseudoRoo t()):
if prim.HasAPI(UsdPhysics.Collision API) and prim.GetTypeName() == "Xform":
for child in prim.GetAllChildren():
if child.GetTypeName() == "Mesh" and not child.HasAPI(UsdPhysics.Collisio nAPI):
UsdPhysics.CollisionAPI.Apply(ch ild)
UsdPhysics.MeshCollisionAPI.Appl y(child)
print(f"Applied CollisionAPI to: {child.GetPath()}")
Important: The two phases must be separate passes. Modifying instanceable while iterating over instance proxies will raise a RuntimeError about expired instance proxy prims.
After running, toggle Show by Type → Physics → Colliders off and on. You should see red wireframes on all arm links.
To summarize the root cause on 5.1: the URDF importer applies CollisionAPI to an Xform container rather than the Mesh prim inside it, and marks the collision subtrees as instanceable. Both of these prevent the viewport overlay from rendering
wireframes. In 6.0, the first issue is fixed (CollisionAPI is placed directly on Mesh prims), but the instanceable issue remains — the asset transformer still marks collision geometry as instanceable, so you’d still need to uncheck
Instanceable on those prims to see wireframes.
Root cause (Isaac Sim 5.1): The URDF importer applies PhysicsCollisionAPI to the Xform container prim (e.g. node_STL_BINARY_) rather than the child Mesh prim. The viewport collision wireframe overlay finds prims with CollisionAPI via Fabric and needs geometry on that prim to draw — but an Xform has no geometry. The overlay can look at children to find
geometry, but only if they’re regular prims; instance proxy children (behind an instanceable boundary) can’t be traversed this way. Since the 5.1 importer also marks the collision subtrees instanceable=true, the combination of both makes wireframes invisible.
Two workarounds for 5.1:
Option A — Disable instanceable (simpler, UI-based):
Select the collisions prim on each link in the Stage tree, then uncheck Instanceable in the Property panel. This allows the overlay to find geometry in the children of the CollisionAPI Xform.
Option B — Apply CollisionAPI to Mesh prims (more correct):
from pxr import Usd, UsdGeom, UsdPhysics
import omni.usd
stage = omni.usd.get_context().get_stage ()
for prim in Usd.PrimRange(stage.GetPseudoRoo t(), Usd.TraverseInstanceProxies()):
if prim.HasAPI(UsdPhysics.Collision API) and prim.GetTypeName() == "Xform":
for child in Usd.PrimRange(prim, Usd.TraverseInstanceProxies()):
if child.IsA(UsdGeom.Gprim) and not child.HasAPI(UsdPhysics.Collisio nAPI):
UsdPhysics.CollisionAPI.Apply(ch ild)
if child.GetTypeName() == "Mesh":
UsdPhysics.MeshCollisionAPI.Appl y(child)
print(f"Applied CollisionAPI to: {child.GetPath()}")
After running, toggle Show by Type → Physics → Colliders off and on.
Red wireframes are expected for STL-based collision geometry — they indicate triangle mesh collision. Green = convex hull, blue = SDF mesh.
Fixed in Isaac Sim 6.0: The rewritten URDF importer applies CollisionAPI directly to geometry prims (Mesh, Cube, Sphere, etc.), so collider visualization works out of the box regardless of the instanceable flag.