Importing USD assets#
Universal Scene Description (USD) is Pixar’s open framework for describing and composing 3D scenes. Genesis World imports USD files (.usd, .usda, .usdc, .usdz) through gs.morphs.USD, reading geometry, materials, and UsdPhysics joint definitions. A single file may hold one articulated robot, one rigid object, or a whole environment of many entities, like the assets that NVIDIA Isaac Sim and similar tools export.
Two runnable examples are the source of truth for this page:
examples/usd/import_stage.py: load a single articulated asset and animate its joints.examples/usd/kitchen.py: load a multi-entity kitchen scene with per-asset processing options.
Installation#
USD parsing needs the usd optional dependency:
pip install -e ".[usd]"
That installs usd-core, which is enough to read USD files and their UsdPreviewSurface materials. For assets whose materials use other shaders, see material baking below.
Minimal working example#
The following loads a refrigerator asset and steps the simulation. It downloads the asset from the Genesis World asset repository on Hugging Face on first run:
import genesis as gs
from huggingface_hub import snapshot_download
gs.init(backend=gs.cpu)
scene = gs.Scene(show_viewer=True)
scene.add_entity(gs.morphs.Plane())
asset_path = snapshot_download(
repo_type="dataset",
repo_id="Genesis-Intelligence/assets",
revision="c50bfe3e354e105b221ef4eb9a79504650709dd2",
allow_patterns="usd/Refrigerator055/*",
max_workers=1,
)
entities = scene.add_stage(
morph=gs.morphs.USD(
file=f"{asset_path}/usd/Refrigerator055/Refrigerator055.usd",
pos=(0, 0, 0.9),
euler=(0, 0, 180), # extrinsic x-y-z, degrees
),
)
scene.build()
for _ in range(1000):
scene.step()
add_stage returns a list of the entities it created, one per rigid body or articulation found in the file. The refrigerator is a single articulation, so the list has one element; a room scene returns many. See Hello, Genesis World for the initialize / scene / build / step lifecycle that every Genesis World program shares.
add_stage vs. add_entity#
A USD file is a stage that can contain any number of physics entities. Genesis World offers two entry points:
scene.add_stage(morph=gs.morphs.USD(...))discovers and loads every rigid entity in the file and returns them as a list. Use it for complete scenes and for any file whose contents you don’t want to enumerate by hand.scene.add_entity(gs.morphs.USD(...))loads a single entity and returns it directly. It targets the prim named byprim_path; whenprim_pathis left asNone, it falls back to the stage’s default prim, and raises if the file declares none.
Both accept the same gs.morphs.USD morph, so every option below applies to either path.
Articulations and rigid bodies#
Genesis World parses UsdPhysics joints into a dof graph. Rigid bodies with no joints between them become free bodies; bodies connected by joints become one articulation. The supported joint types are:
USD schema |
Genesis World joint |
Degrees of freedom |
|---|---|---|
|
revolute |
1 rotational, with limits |
|
prismatic |
1 translational, with limits |
|
spherical |
3 rotational |
|
fixed |
0 (rigid link-to-link weld) |
|
free |
6 (full translation + rotation) |
A joint’s root link is fixed or floating according to the asset. Override this with fixed on the morph, which applies only to root (base) links:
gs.morphs.USD(file="robot.usd", fixed=True) # weld the base to the world
examples/usd/kitchen.py uses fixed=False so authored-fixed appliances such as the dishwasher become free bodies that drop onto the ground and can be dragged, and fixed=None to keep the scene’s authored fixed/free states.
Axis and units#
USD stages carry their own upAxis and metersPerUnit metadata, and Genesis World honors it when transforming the asset into its right-handed, Z-up, meters world. When a referenced mesh omits that information, the file_meshes_are_zup morph option controls interpretation the same way it does for other mesh formats. See Conventions for the full axis- and unit-handling rules, including the Blender-aligned Y-up ↔ Z-up mapping Genesis World follows.
Mesh processing#
Collision meshes are derived from the asset’s geometry. Three options control that derivation; examples/usd/kitchen.py sets all three to honor the asset as authored:
scene.add_stage(
morph=gs.morphs.USD(
file=usd_file,
fixed=fixed,
convexify=False, # Don't force convex hulls; honor the asset's per-geom MeshCollisionAPI approximation.
decimate=True, # Simplify collision meshes (fewer faces) for speed and stability.
align=False, # Keep the USD root-link frames (don't re-center to the center of mass).
),
vis_mode="visual", # Render the asset's own USD materials, not the per-collision debug colors.
)
convexifywraps each mesh in one or more convex hulls (decomposing withcoacdwhen a single hull is too coarse). It defaults toTruefor rigid entities. Set it toFalseto keep concave collision geometry the asset already provides.decimatesimplifies collision meshes towarddecimate_face_num(default 500) faces. It defaults toTruewhenconvexifyis on.alignre-frames floating-base root links so the origin sits at the center of mass. It defaults toFalse.
vis_mode="collision" renders the collision geometry instead of the visual meshes, which is the fastest way to check that collision shapes match what you expect.
Joint dynamics attributes#
Some joint properties (friction, armature, passive stiffness and damping) are not part of the core USD physics schema, so exporters store them under custom attribute names. Isaac Sim, for example, writes physxJoint:jointFriction and physxLimit:angular:stiffness. Genesis World reads each property from a list of candidate attribute names, trying them in order and using the first that exists:
gs.morphs.USD(
file="robot.usd",
joint_friction_attr_candidates=[
"physxJoint:jointFriction", # Isaac Sim
"physics:jointFriction",
"jointFriction",
"friction",
],
)
The defaults already cover Isaac Sim and common community conventions; override a candidate list only when your exporter uses a name none of them match. The parsed values populate the corresponding dof fields:
Morph option |
|
Meaning |
|---|---|---|
|
|
passive joint friction |
|
|
reflected rotor inertia |
|
|
passive stiffness (revolute) |
|
|
passive damping (revolute) |
|
|
passive stiffness (prismatic) |
|
|
passive damping (prismatic) |
PD control gains authored through the USD PhysicsDriveAPI (physics:stiffness, physics:angular:damping) are read into dofs_kp and dofs_kv directly, since those are standard USD attributes.
Separating visual and collision geometry#
When an asset does not declare collision geometry through MeshCollisionAPI, Genesis World infers it from prim names. It matches each prim against regex patterns and inherits the match down the subtree:
gs.morphs.USD(
file="robot.usd",
collision_mesh_prim_patterns=[r"^([cC]ollision).*"], # collision-only geometry
visual_mesh_prim_patterns=[r"^([vV]isual).*"], # visual-only geometry
)
The rules, in order of application:
Inheritance. The parser traverses the prim hierarchy top-down. Once a prim matches a pattern, every descendant inherits that classification.
Classification. A prim matching only the visual pattern is visual-only; one matching only the collision pattern is collision-only; one matching both, or neither, is used for both. The neither case is the default for mesh-only assets that carry no naming convention.
Visibility and purpose. Only visible prims are parsed. Prims with
purpose = "guide"are excluded from visuals but may still serve as collision geometry.
The patterns above are the defaults, so most Isaac Sim assets need no configuration here.
Material baking#
usd-core parses UsdPreviewSurface materials, which covers most assets. Materials built on other shader networks require NVIDIA Omniverse Kit to bake them into a supported form. Baking is available on Python 3.10 and 3.11 with a GPU backend:
pip install --extra-index-url https://pypi.nvidia.com/ omniverse-kit
export OMNI_KIT_ACCEPT_EULA=yes
OMNI_KIT_ACCEPT_EULA=yes accepts the Omniverse EULA non-interactively; set it once. Without Omniverse Kit, Genesis World parses only UsdPreviewSurface and falls back to each prim’s displayColor where no material is present.
Note
If you see a Baking process failed: ... warning, the usual causes are an unaccepted EULA (set OMNI_KIT_ACCEPT_EULA=yes), a first-launch dependency install that timed out (rerun the program once it finishes), or stale extensions across multiple Python environments (remove the shared extension folder, e.g. ~/.local/share/ov/data/ext on Linux, and retry).
See also#
Conventions: coordinate frame, units, and Y-up ↔ Z-up handling.
Control your robot and Inverse kinematics and motion planning: actuating and planning for a USD-loaded articulation.
Parallel simulation: running USD assets across many environments on the GPU.
Morph: the full
gs.morphsreference, including everyUSDoption.