Frequently Used Python Snippets

A collection of python utility snippets that can be used in the script editor or pure python applications

Create A Physics Scene

1import omni
2from pxr import Gf, Sdf, UsdPhysics
3
4stage = omni.usd.get_context().get_stage()
5# Add a physics scene prim to stage
6scene = UsdPhysics.Scene.Define(stage, Sdf.Path("/World/physicsScene"))
7# Set gravity vector
8scene.CreateGravityDirectionAttr().Set(Gf.Vec3f(0.0, 0.0, -1.0))
9scene.CreateGravityMagnitudeAttr().Set(981.0)

The following can be added to set specific settings, in this case use CPU physics and the TGS solver

1from pxr import PhysxSchema
2
3PhysxSchema.PhysxSceneAPI.Apply(stage.GetPrimAtPath("/World/physicsScene"))
4physxSceneAPI = PhysxSchema.PhysxSceneAPI.Get(stage, "/World/physicsScene")
5physxSceneAPI.CreateEnableCCDAttr(True)
6physxSceneAPI.CreateEnableStabilizationAttr(True)
7physxSceneAPI.CreateEnableGPUDynamicsAttr(False)
8physxSceneAPI.CreateBroadphaseTypeAttr("MBP")
9physxSceneAPI.CreateSolverTypeAttr("TGS")

Adding a ground plane to a stage can be done via the following code: It creates a Z up plane with a size of 100 cm at a Z coordinate of -100

1import omni
2from pxr import PhysicsSchemaTools
3stage = omni.usd.get_context().get_stage()
4PhysicsSchemaTools.addGroundPlane(stage, "/World/groundPlane", "Z", 100, Gf.Vec3f(0, 0, -100), Gf.Vec3f(1.0))

Enable Physics And Collision For a Mesh

The script below assumes there is a physics scene in the stage.

 1import omni
 2from omni.physx.scripts import utils
 3
 4# Create a cube mesh in the stage
 5stage = omni.usd.get_context().get_stage()
 6result, path = omni.kit.commands.execute("CreateMeshPrimCommand", prim_type="Cube")
 7# Get the prim
 8cube_prim = stage.GetPrimAtPath("/Cube")
 9# Enable physics on prim
10# If a tighter collision approximation is desired use convexDecomposition instead of convexHull
11utils.setRigidBody(cube_prim, "convexHull", False)

If a tighter collision approximation is desired use convexDecomposition

 1import omni
 2from omni.physx.scripts import utils
 3
 4# Create a cube mesh in the stage
 5stage = omni.usd.get_context().get_stage()
 6result, path = omni.kit.commands.execute("CreateMeshPrimCommand", prim_type="Cube")
 7# Get the prim
 8cube_prim = stage.GetPrimAtPath("/Cube")
 9# Enable physics on prim
10# If a tighter collision approximation is desired use convexDecomposition instead of convexHull
11utils.setRigidBody(cube_prim, "convexDecomposition", False)

To verify that collision meshes have been successfully enabled, click the “eye” icon > “Show By Type” > “Physics Mesh” > “All”. This will show the collision meshes as pink outlines on the objects.

Set Mass Properties for a Mesh

The snippet below shows how to set the mass of a physics object. Density can also be specified as an alternative

 1import omni
 2from pxr import UsdPhysics
 3from omni.physx.scripts import utils
 4
 5stage = omni.usd.get_context().get_stage()
 6result, path = omni.kit.commands.execute("CreateMeshPrimCommand", prim_type="Cube")
 7# Get the prim
 8cube_prim = stage.GetPrimAtPath(path)
 9# Make it a rigid body
10utils.setRigidBody(cube_prim, "convexHull", False)
11
12mass_api = UsdPhysics.MassAPI.Apply(cube_prim)
13mass_api.CreateMassAttr(10)
14### Alternatively set the density
15mass_api.CreateDensityAttr(1000)

Traverse a stage and assign collision meshes to children

 1import omni
 2from pxr import Usd, UsdGeom, Gf
 3from omni.physx.scripts import utils
 4
 5stage = omni.usd.get_context().get_stage()
 6
 7def add_cube(stage, path, size: float = 10, offset: Gf.Vec3d = Gf.Vec3d(0, 0, 0)):
 8    cubeGeom = UsdGeom.Cube.Define(stage, path)
 9    cubeGeom.CreateSizeAttr(size)
10    cubeGeom.AddTranslateOp().Set(offset)
11
12### The following prims are added for illustrative purposes
13result, path = omni.kit.commands.execute("CreateMeshPrimCommand", prim_type="Torus")
14# all prims under AddCollision will get collisions assigned
15add_cube(stage, "/World/Cube_0", offset=Gf.Vec3d(100, 100, 0))
16# create a prim nested under without a parent
17add_cube(stage, "/World/Nested/Cube", offset=Gf.Vec3d(100, 0, 100))
18###
19
20# Traverse all prims in the stage starting at this path
21curr_prim = stage.GetPrimAtPath("/")
22
23for prim in Usd.PrimRange(curr_prim):
24    # only process shapes and meshes
25    if (
26        prim.IsA(UsdGeom.Cylinder)
27        or prim.IsA(UsdGeom.Capsule)
28        or prim.IsA(UsdGeom.Cone)
29        or prim.IsA(UsdGeom.Sphere)
30        or prim.IsA(UsdGeom.Cube)
31    ):
32        # use a ConvexHull for regular prims
33        utils.setCollider(prim, approximationShape="convexHull")
34    elif prim.IsA(UsdGeom.Mesh):
35        # "None" will use the base triangle mesh if available
36        # Can also use "convexDecomposition", "convexHull", "boundingSphere", "boundingCube"
37        utils.setCollider(prim, approximationShape="None")
38    pass
39pass

Do Overlap Test

These snippets detect and report when objects overlap with a specified cubic/spherical region. The following is assumed: the stage contains a physics scene, all objects have collision meshes enabled, and the play button has been clicked.

The parameters: extent, origin and rotation (or origin and radius) define the cubic/spherical region to check overlap against. The output of the physX query is the number of objects that overlaps with this cubic/spherical region.

 1def check_overlap_box(self):
 2    # Defines a cubic region to check overlap with
 3    extent = carb.Float3(20.0, 20.0, 20.0)
 4    origin = carb.Float3(0.0, 0.0, 0.0)
 5    rotation = carb.Float4(0.0, 0.0, 1.0, 0.0)
 6    # physX query to detect number of hits for a cubic region
 7    numHits = get_physx_scene_query_interface().overlap_box(extent, origin, rotation, self.report_hit, False)
 8    # physX query to detect number of hits for a spherical region
 9    # numHits = get_physx_scene_query_interface().overlap_sphere(radius, origin, self.report_hit, False)
10    self.kit.update()
11    return numHits > 0:
 1import omni.physx
 2from omni.physx import get_physx_scene_query_interface
 3from pxr import UsdGeom, Gf, Vt
 4import carb
 5
 6def report_hit(self, hit):
 7    # When a collision is detected, the object color changes to red.
 8    hitColor = Vt.Vec3fArray([Gf.Vec3f(180.0 / 255.0, 16.0 / 255.0, 0.0)])
 9    usdGeom = UsdGeom.Mesh.Get(self.stage, hit.rigid_body)
10    usdGeom.GetDisplayColorAttr().Set(hitColor)
11    return True

Do Raycast Test

This snippet detects the closest object that intersects with a specified ray. The following is assumed: the stage contains a physics scene, all objects have collision meshes enabled, and the play button has been clicked.

The parameters: origin, rayDir and distance define a ray along which a ray hit might be detected. The output of the query can be used to access the object’s reference, and its distance from the raycast origin.

 1import omni.physx
 2from omni.physx import get_physx_scene_query_interface
 3from pxr import UsdGeom
 4
 5def check_raycast(self):
 6    # Projects a raycast from 'origin', in the direction of 'rayDir', for a length of 'distance' cm
 7    # Parameters can be replaced with real-time position and orientation data  (e.g. of a camera)
 8    origin = carb.Float3(0.0, 0.0, 0.0)
 9    rayDir = carb.Float3(1.0, 0.0, 0.0)
10    distance = 100.0
11    # physX query to detect closest hit
12    hit = get_physx_scene_query_interface().raycast_closest(origin, rayDir, distance)
13    if(hit["hit"]):
14        # Change object color to yellow and record distance from origin
15        usdGeom = UsdGeom.Mesh.Get(self.stage, hit["rigidBody"])
16        hitColor = Vt.Vec3fArray([Gf.Vec3f(255.0 / 255.0, 255.0 / 255.0, 0.0)])
17        usdGeom.GetDisplayColorAttr().Set(hitColor)
18        distance = hit["distance"]
19        return usdGeom.GetPath().pathString, distance
20    return None, 10000.0

Creating, Modifying, Assigning Materials

 1import omni
 2from pxr import UsdShade, Sdf, Gf
 3
 4mtl_created_list = []
 5# Create a new material using OmniGlass.mdl
 6omni.kit.commands.execute(
 7    "CreateAndBindMdlMaterialFromLibrary",
 8    mdl_name="OmniGlass.mdl",
 9    mtl_name="OmniGlass",
10    mtl_created_list=mtl_created_list,
11)
12# Get reference to created material
13stage = omni.usd.get_context().get_stage()
14mtl_prim = stage.GetPrimAtPath(mtl_created_list[0])
15# Set material inputs, these can be determined by looking at the .mdl file
16# or by selecting the Shader attached to the Material in the stage window and looking at the details panel
17omni.usd.create_material_input(mtl_prim, "glass_color", Gf.Vec3f(0, 1, 0), Sdf.ValueTypeNames.Color3f)
18omni.usd.create_material_input(mtl_prim, "glass_ior", 1.0, Sdf.ValueTypeNames.Float)
19# Create a prim to apply the material to
20result, path = omni.kit.commands.execute("CreateMeshPrimCommand", prim_type="Cube")
21# Get the path to the prim
22cube_prim = stage.GetPrimAtPath(path)
23# Bind the material to the prim
24cube_mat_shade = UsdShade.Material(mtl_prim)
25UsdShade.MaterialBindingAPI(cube_prim).Bind(cube_mat_shade, UsdShade.Tokens.strongerThanDescendants)

Assigning a texture to a material that supports it can be done as follows:

 1import omni
 2import carb
 3from pxr import UsdShade, Sdf
 4
 5# Change the server to your Nucleus install, default is set to localhost in omni.isaac.sim.base.kit
 6default_server = carb.settings.get_settings().get("/persistent/isaac/asset_root/default")
 7mtl_created_list = []
 8# Create a new material using OmniPBR.mdl
 9omni.kit.commands.execute(
10    "CreateAndBindMdlMaterialFromLibrary",
11    mdl_name="OmniPBR.mdl",
12    mtl_name="OmniPBR",
13    mtl_created_list=mtl_created_list,
14)
15stage = omni.usd.get_context().get_stage()
16mtl_prim = stage.GetPrimAtPath(mtl_created_list[0])
17# Set material inputs, these can be determined by looking at the .mdl file
18# or by selecting the Shader attached to the Material in the stage window and looking at the details panel
19omni.usd.create_material_input(
20    mtl_prim,
21    "diffuse_texture",
22    default_server + "/Isaac/Samples/DR/Materials/Textures/marble_tile.png",
23    Sdf.ValueTypeNames.Asset,
24)
25# Create a prim to apply the material to
26result, path = omni.kit.commands.execute("CreateMeshPrimCommand", prim_type="Cube")
27# Get the path to the prim
28cube_prim = stage.GetPrimAtPath(path)
29# Bind the material to the prim
30cube_mat_shade = UsdShade.Material(mtl_prim)
31UsdShade.MaterialBindingAPI(cube_prim).Bind(cube_mat_shade, UsdShade.Tokens.strongerThanDescendants)

Adding a transform matrix to a prim

 1import omni
 2from pxr import Gf, UsdGeom
 3
 4# Create a cube mesh in the stage
 5stage = omni.usd.get_context().get_stage()
 6result, path = omni.kit.commands.execute("CreateMeshPrimCommand", prim_type="Cube")
 7# Get the prim and set its transform matrix
 8cube_prim = stage.GetPrimAtPath("/World/Cube")
 9xform = UsdGeom.Xformable(cube_prim)
10transform = xform.AddTransformOp()
11mat = Gf.Matrix4d()
12mat.SetTranslateOnly(Gf.Vec3d(10.0,1.0,1.0))
13mat.SetRotateOnly(Gf.Rotation(Gf.Vec3d(0,1,0), 290))
14transform.Set(mat)

Align two USD prims

 1import omni
 2from pxr import UsdGeom, Gf
 3
 4stage = omni.usd.get_context().get_stage()
 5# Create a cube
 6result, path_a = omni.kit.commands.execute("CreateMeshPrimCommand", prim_type="Cube")
 7prim_a = stage.GetPrimAtPath(path_a)
 8# change the cube pose
 9xform = UsdGeom.Xformable(prim_a)
10transform = xform.AddTransformOp()
11mat = Gf.Matrix4d()
12mat.SetTranslateOnly(Gf.Vec3d(10.0, 1.0, 1.0))
13mat.SetRotateOnly(Gf.Rotation(Gf.Vec3d(0, 1, 0), 290))
14transform.Set(mat)
15# Create a second cube
16result, path_b = omni.kit.commands.execute("CreateMeshPrimCommand", prim_type="Cube")
17prim_b = stage.GetPrimAtPath(path_b)
18# Get the transform of the first cube
19pose = omni.usd.utils.get_world_transform_matrix(prim_a)
20# Clear the transform on the second cube
21xform = UsdGeom.Xformable(prim_b)
22xform.ClearXformOpOrder()
23# Set the pose of prim_b to that of prim_b
24xform_op = xform.AddXformOp(UsdGeom.XformOp.TypeTransform, UsdGeom.XformOp.PrecisionDouble, "")
25xform_op.Set(pose)

Get World Transform At Current Timestamp For Selected Prims

 1import omni
 2from pxr import UsdGeom, Gf
 3
 4usd_context = omni.usd.get_context()
 5stage = usd_context.get_stage()
 6
 7#### For testing purposes we create and select a prim
 8#### This section can be removed if you already have a prim selected
 9result, path = omni.kit.commands.execute("CreateMeshPrimCommand", prim_type="Cube")
10cube_prim = stage.GetPrimAtPath(path)
11# change the cube pose
12xform = UsdGeom.Xformable(cube_prim)
13transform = xform.AddTransformOp()
14mat = Gf.Matrix4d()
15mat.SetTranslateOnly(Gf.Vec3d(10.0, 1.0, 1.0))
16mat.SetRotateOnly(Gf.Rotation(Gf.Vec3d(0, 1, 0), 290))
17transform.Set(mat)
18omni.usd.get_context().get_selection().set_prim_path_selected(path, True, True, True, False)
19####
20
21# Get list of selected primitives
22selected_prims = usd_context.get_selection().get_selected_prim_paths()
23# Get the current timecode
24timeline = omni.timeline.get_timeline_interface()
25timecode = timeline.get_current_time() * timeline.get_time_codes_per_seconds()
26# Loop through all prims and print their transforms
27for s in selected_prims:
28    curr_prim = stage.GetPrimAtPath(s)
29    print("Selected", s)
30    pose = omni.usd.utils.get_world_transform_matrix(curr_prim, timecode)
31    print("Matrix Form:", pose)
32    print("Translation: ", pose.ExtractTranslation())
33    q = pose.ExtractRotation().GetQuaternion()
34    print(
35        "Rotation: ", q.GetReal(), ",", q.GetImaginary()[0], ",", q.GetImaginary()[1], ",", q.GetImaginary()[2]
36    )

Save current stage to USD

This can be useful if generating a stage in python and you want to store it to reload later to debugging

1import omni
2import carb
3
4# Change server below to your nucleus install
5default_server = carb.settings.get_settings().get("/persistent/isaac/asset_root/default")
6# Create a prim
7result, path = omni.kit.commands.execute("CreateMeshPrimCommand", prim_type="Cube")
8# Change the path as needed
9omni.usd.get_context().save_as_stage(default_server + "/Users/test/saved.usd", None)

Simple Async Task

 1import asyncio
 2import omni
 3
 4# Async task that pauses simulation once the incoming task is complete
 5async def pause_sim(task):
 6    done, pending = await asyncio.wait({task})
 7    if task in done:
 8        print("Waited until next frame, pausing")
 9        omni.timeline.get_timeline_interface().pause()
10
11# Start simulation, then wait a frame and run the pause_sim task
12omni.timeline.get_timeline_interface().play()
13task = asyncio.ensure_future(omni.kit.app.get_app().next_update_async())
14asyncio.ensure_future(pause_sim(task))

Multi-Camera

The below script will create multiple viewports (render products with different resolution and camera poses for each viewport). Once created, rgb images from each render product are saved to disk by accesing the data using a custom replicator writer or the built-in annotators.

  1from omni.isaac.kit import SimulationApp
  2
  3simulation_app = SimulationApp()
  4
  5import os
  6import omni.kit
  7import numpy as np
  8from PIL import Image
  9from pxr import UsdGeom
 10
 11import omni.replicator.core as rep
 12from omni.replicator.core import Writer, AnnotatorRegistry
 13
 14NUM_FRAMES = 5
 15
 16# Save rgb image to file
 17def save_rgb(rgb_data, file_name):
 18    rgb_image_data = np.frombuffer(rgb_data, dtype=np.uint8).reshape(*rgb_data.shape, -1)
 19    rgb_img = Image.fromarray(rgb_image_data, "RGBA")
 20    rgb_img.save(file_name + ".png")
 21
 22
 23# Randomize cube color every frame using a replicator randomizer
 24def cube_color_randomizer():
 25    cube_prims = rep.get.prims(path_pattern="Cube")
 26    with cube_prims:
 27        rep.randomizer.color(colors=rep.distribution.uniform((0, 0, 0), (1, 1, 1)))
 28    return cube_prims.node
 29
 30
 31# Access data through a custom replicator writer
 32class MyWriter(Writer):
 33    def __init__(self, rgb: bool = True):
 34        self._frame_id = 0
 35        if rgb:
 36            self.annotators.append(AnnotatorRegistry.get_annotator("rgb"))
 37        # Create writer output directory
 38        self.file_path = os.path.join(os.getcwd(), "_out_writer", "")
 39        print(f"Writing writer data to {self.file_path}")
 40        dir = os.path.dirname(self.file_path)
 41        os.makedirs(dir, exist_ok=True)
 42
 43    def write(self, data):
 44        for annotator in data.keys():
 45            annotator_split = annotator.split("-")
 46            if len(annotator_split) > 1:
 47                render_product_name = annotator_split[-1]
 48            if annotator.startswith("rgb"):
 49                save_rgb(data[annotator], f"{self.file_path}/{render_product_name}_frame_{self._frame_id}")
 50        self._frame_id += 1
 51
 52
 53rep.WriterRegistry.register(MyWriter)
 54
 55stage = omni.usd.get_context().get_stage()
 56
 57# Create cube
 58cube_prim = stage.DefinePrim("/World/Cube", "Cube")
 59UsdGeom.Xformable(cube_prim).AddTranslateOp().Set((0., 5., 1.))
 60
 61# Register cube color randomizer to trigger on every frame
 62rep.randomizer.register(cube_color_randomizer)
 63with rep.trigger.on_frame():
 64    rep.randomizer.cube_color_randomizer()
 65
 66# Create cameras
 67camera_prim1 = stage.DefinePrim("/World/Camera1", "Camera")
 68UsdGeom.Xformable(camera_prim1).AddTranslateOp().Set((0., 10., 20.))
 69UsdGeom.Xformable(camera_prim1).AddRotateXYZOp().Set((-15., 0., 0.))
 70
 71camera_prim2 = stage.DefinePrim("/World/Camera2", "Camera")
 72UsdGeom.Xformable(camera_prim2).AddTranslateOp().Set((-10., 15., 15.))
 73UsdGeom.Xformable(camera_prim2).AddRotateXYZOp().Set((-45., 0., 45.))
 74
 75# Create render products
 76rp1 = rep.create.render_product(str(camera_prim1.GetPrimPath()), resolution=(320, 320))
 77rp2 = rep.create.render_product(str(camera_prim2.GetPrimPath()), resolution=(640, 640))
 78rp3 = rep.create.render_product("/OmniverseKit_Persp", (1024, 1024))
 79
 80# Acess the data through a custom writer
 81writer = rep.WriterRegistry.get("MyWriter")
 82writer.initialize(rgb=True)
 83writer.attach([rp1, rp2, rp3])
 84
 85# Acess the data through annotators
 86rgb_annotators = []
 87for rp in [rp1, rp2, rp3]:
 88    rgb = rep.AnnotatorRegistry.get_annotator("rgb")
 89    rgb.attach([rp])
 90    rgb_annotators.append(rgb)
 91
 92# NOTE A list of render products will be supported in the near future, currently only the first render product in the list will be used
 93# rgb = rep.AnnotatorRegistry.get_annotator("rgb")
 94# rgb.attach([rp1, rp2, rp3])
 95
 96# Create annotator output directory
 97file_path = os.path.join(os.getcwd(), "_out_annot", "")
 98print(f"Writing annotator data to {file_path}")
 99dir = os.path.dirname(file_path)
100os.makedirs(dir, exist_ok=True)
101
102for i in range(NUM_FRAMES):
103    rep.orchestrator.step()
104    # Get annotator data after each replicator process step
105    for j, rgb_annot in enumerate(rgb_annotators):
106        save_rgb(rgb_annot.get_data(), f"{dir}/rp{j}_step_{i}")
107
108simulation_app.close()

Get synthetic data at custom events in simulations

The below script will use annotators to access synthetic data at specific timepoints during simulations.

Note

Triggering built-in Replicator writers at custom events will be supported in future releases.

 1from omni.isaac.kit import SimulationApp
 2
 3simulation_app = SimulationApp(launch_config={"renderer": "RayTracedLighting", "headless": False})
 4
 5import omni
 6import numpy as np
 7import os
 8import json
 9from PIL import Image
10from omni.isaac.core import World
11from omni.isaac.core.objects import DynamicCuboid
12import omni.replicator.core as rep
13from omni.isaac.core.utils.semantics import add_update_semantics
14
15# Util function to save rgb annotator data
16def write_rgb_data(rgb_data, file_path):
17    rgb_image_data = np.frombuffer(rgb_data, dtype=np.uint8).reshape(*rgb_data.shape, -1)
18    rgb_img = Image.fromarray(rgb_image_data, "RGBA")
19    rgb_img.save(file_path + ".png")
20
21
22# Util function to save semantic segmentation annotator data
23def write_sem_data(sem_data, file_path):
24    id_to_labels = sem_data["info"]["idToLabels"]
25    with open(file_path + ".json", "w") as f:
26        json.dump(id_to_labels, f)
27    sem_image_data = np.frombuffer(sem_data["data"], dtype=np.uint8).reshape(*sem_data["data"].shape, -1)
28    sem_img = Image.fromarray(sem_image_data, "RGBA")
29    sem_img.save(file_path + ".png")
30
31
32# Create a new stage with the default ground plane
33omni.usd.get_context().new_stage()
34world = World()
35world.scene.add_default_ground_plane()
36world.reset()
37
38# Run the application for several frames to allow the materials to load
39for i in range(20):
40    simulation_app.update()
41
42# Create a camera and render product to collect the data from
43cam = rep.create.camera(position=(3, 3, 3), look_at=(0, 0, 0))
44rp = rep.create.render_product(cam, (512, 512))
45
46# Set the output directory for the data
47out_dir = os.getcwd() + "/_out_sim_get_data"
48os.makedirs(out_dir, exist_ok=True)
49print(f"Outputting data to {out_dir}..")
50
51# NOTE currently replicator writers do not work correctly with isaac simulations and will interfere with the timeline
52# writer = rep.WriterRegistry.get("BasicWriter")
53# writer.initialize(output_dir=out_dir, rgb=True, semantic_segmentation=True, colorize_semantic_segmentation=True)
54# writer.attach([rp])
55
56# Accesing the data directly from annotators
57rgb_annot = rep.AnnotatorRegistry.get_annotator("rgb")
58rgb_annot.attach([rp])
59sem_annot = rep.AnnotatorRegistry.get_annotator("semantic_segmentation", init_params={"colorize": True})
60sem_annot.attach([rp])
61
62for i in range(5):
63    cuboid = world.scene.add(DynamicCuboid(prim_path=f"/World/Cuboid_{i}", name=f"Cuboid_{i}", position=(0, 0, 10 + i)))
64    add_update_semantics(cuboid.prim, "Cuboid")
65
66    for s in range(1000):
67        world.step(render=True, step_sim=True)
68        vel = np.linalg.norm(cuboid.get_linear_velocity())
69        if vel < 0.1:
70            print(f"Cube_{i} stopped moving after {s} simulation steps, writing data..")
71            # NOTE replicator's step is no longer needed since new data is fed in the annotators every world.step()
72            # rep.orchestrator.step()
73            write_rgb_data(rgb_annot.get_data(), f"{out_dir}/Cube_{i}_step_{s}_rgb")
74            write_sem_data(sem_annot.get_data(), f"{out_dir}/Cube_{i}_step_{s}_sem")
75            break
76
77simulation_app.close()

Convert Asset to USD

The below script will convert a non-USD asset like OBJ/STL/FBX to USD. This is meant to be used inside the Script Editor. For running it as a Standalone Application, an example can be found in standalone_examples/api/omni.kit.asset_converter/.

 1import carb
 2import omni
 3import asyncio
 4
 5
 6async def convert_asset_to_usd(input_obj: str, output_usd: str):
 7    import omni.kit.asset_converter
 8
 9    def progress_callback(progress, total_steps):
10        pass
11
12    converter_context = omni.kit.asset_converter.AssetConverterContext()
13    # setup converter and flags
14    # converter_context.ignore_material = False
15    # converter_context.ignore_animation = False
16    # converter_context.ignore_cameras = True
17    # converter_context.single_mesh = True
18    # converter_context.smooth_normals = True
19    # converter_context.preview_surface = False
20    # converter_context.support_point_instancer = False
21    # converter_context.embed_mdl_in_usd = False
22    # converter_context.use_meter_as_world_unit = True
23    # converter_context.create_world_as_default_root_prim = False
24    instance = omni.kit.asset_converter.get_instance()
25    task = instance.create_converter_task(input_obj, output_usd, progress_callback, converter_context)
26    success = await task.wait_until_finished()
27    if not success:
28        carb.log_error(task.get_status(), task.get_detailed_error())
29    print("converting done")
30
31
32asyncio.ensure_future(
33    convert_asset_to_usd(
34        "</path/to/mesh.obj>",
35        "</path/to/mesh.usd>",
36    )
37)

The details about the optional import options in lines 13-23 can be found here.

Get Camera Parameters

The below script show how to get the camera parameters associated with a viewport.

 1import omni
 2from omni.syntheticdata import helpers
 3import math
 4
 5stage = omni.usd.get_context().get_stage()
 6viewport_api = omni.kit.viewport.utility.get_active_viewport()
 7# Set viewport resolution, changes will occur on next frame
 8viewport_api.set_texture_resolution((512, 512))
 9# get resolution
10(width, height) = viewport_api.get_texture_resolution()
11aspect_ratio = width / height
12# get camera prim attached to viewport
13camera = stage.GetPrimAtPath(viewport_api.get_active_camera())
14focal_length = camera.GetAttribute("focalLength").Get()
15horiz_aperture = camera.GetAttribute("horizontalAperture").Get()
16vert_aperture = camera.GetAttribute("verticalAperture").Get()
17# Pixels are square so we can also do:
18# vert_aperture = height / width * horiz_aperture
19near, far = camera.GetAttribute("clippingRange").Get()
20fov = 2 * math.atan(horiz_aperture / (2 * focal_length))
21# helper to compute projection matrix
22proj_mat = helpers.get_projection_matrix(fov, aspect_ratio, near, far)
23
24# compute focal point and center
25focal_x = height * focal_length / vert_aperture
26focal_y = width * focal_length / horiz_aperture
27center_x = height * 0.5
28center_y = width * 0.5

Get Size of a Mesh

The snippet below shows how to get the size of a mesh.

 1import omni
 2from pxr import Usd, UsdGeom, Gf
 3
 4stage = omni.usd.get_context().get_stage()
 5result, path = omni.kit.commands.execute("CreateMeshPrimCommand", prim_type="Cone")
 6# Get the prim
 7prim = stage.GetPrimAtPath(path)
 8# Get the size
 9bbox_cache = UsdGeom.BBoxCache(Usd.TimeCode.Default(), includedPurposes=[UsdGeom.Tokens.default_])
10bbox_cache.Clear()
11prim_bbox = bbox_cache.ComputeWorldBound(prim)
12prim_range = prim_bbox.ComputeAlignedRange()
13prim_size = prim_range.GetSize()
14print(prim_size)

Apply Semantic Data on Entire Stage

The snippet below shows how to programatically apply semantic data on objects by iterating the entire stage.

 1import omni.usd
 2from semantics.schema.editor import PrimSemanticData
 3
 4def remove_prefix(name, prefix):
 5    if name.startswith(prefix):
 6        return name[len(prefix):]
 7    return name
 8
 9def remove_numerical_suffix(name):
10    suffix = name.split("_")[-1]
11    if suffix.isnumeric():
12        return name[:-len(suffix) - 1]
13    return name
14
15def remove_underscores(name):
16    return name.replace("_", "")
17
18current_stage = omni.usd.get_context().get_stage()
19for prim in current_stage.Traverse():
20    if prim.GetTypeName() == "Mesh":
21        class_name = str(prim.GetPrimPath()).split("/")[-1]
22        class_name = remove_prefix(class_name, "SM_")
23        class_name = remove_numerical_suffix(class_name)
24        class_name = remove_underscores(class_name)
25        prim_sd = PrimSemanticData(prim)
26        prim_sd.add_entry("class", class_name)