Useful Snippets#

Various examples of Isaac Sim Replicator snippets that can be run as Standalone Applications or from the UI using the Script Editor.

Annotator and Custom Writer Data from Multiple Cameras#

Example on how to access data from multiple cameras in a scene using annotators or custom writers. The standalone example can also be run directly (on Windows use python.bat instead of python.sh):

./python.sh standalone_examples/api/isaacsim.replicator.examples/multi_camera.py
Annotator and Custom Writer Data from Multiple Cameras
  1import asyncio
  2import os
  3import omni.usd
  4import omni.kit
  5import omni.replicator.core as rep
  6import carb.settings
  7from omni.replicator.core import AnnotatorRegistry, Writer
  8from PIL import Image
  9from pxr import UsdGeom, Sdf
 10
 11NUM_FRAMES = 5
 12
 13# Save rgb image to file
 14def save_rgb(rgb_data, file_name):
 15    rgb_img = Image.fromarray(rgb_data).convert("RGBA")
 16    rgb_img.save(file_name + ".png")
 17
 18
 19# Randomize cube color every frame using a replicator randomizer
 20def cube_color_randomizer():
 21    cube_prims = rep.get.prims(path_pattern="Cube")
 22    with cube_prims:
 23        rep.randomizer.color(colors=rep.distribution.uniform((0, 0, 0), (1, 1, 1)))
 24    return cube_prims.node
 25
 26
 27# Access data through a custom replicator writer
 28class MyWriter(Writer):
 29    def __init__(self, rgb: bool = True):
 30        self._frame_id = 0
 31        self.annotators = []
 32        if rgb:
 33            self.annotators.append(AnnotatorRegistry.get_annotator("rgb"))
 34        # Create writer output directory
 35        self.file_path = os.path.join(os.getcwd(), "_out_mc_writer", "")
 36        print(f"Writing writer data to {self.file_path}")
 37        dir = os.path.dirname(self.file_path)
 38        os.makedirs(dir, exist_ok=True)
 39
 40    def write(self, data):
 41        for annotator in data.keys():
 42            annotator_split = annotator.split("-")
 43            if len(annotator_split) > 1:
 44                render_product_name = annotator_split[-1]
 45            if annotator.startswith("rgb"):
 46                save_rgb(data[annotator], f"{self.file_path}/{render_product_name}_frame_{self._frame_id}")
 47        self._frame_id += 1
 48
 49
 50rep.WriterRegistry.register(MyWriter)
 51
 52# Create a new stage with a dome light
 53omni.usd.get_context().new_stage()
 54
 55# Set DLSS to Quality mode (2) for best SDG results (Options: 0 (Performance), 1 (Balanced), 2 (Quality), 3 (Auto)
 56carb.settings.get_settings().set("rtx/post/dlss/execMode", 2)
 57
 58stage = omni.usd.get_context().get_stage()
 59dome_light = stage.DefinePrim("/World/DomeLight", "DomeLight")
 60dome_light.CreateAttribute("inputs:intensity", Sdf.ValueTypeNames.Float).Set(900.0)
 61
 62# Create cube
 63cube_prim = stage.DefinePrim("/World/Cube", "Cube")
 64UsdGeom.Xformable(cube_prim).AddTranslateOp().Set((0.0, 5.0, 1.0))
 65
 66# Register cube color randomizer to trigger on every frame
 67rep.randomizer.register(cube_color_randomizer)
 68with rep.trigger.on_frame():
 69    rep.randomizer.cube_color_randomizer()
 70
 71# Create cameras
 72camera_prim1 = stage.DefinePrim("/World/Camera1", "Camera")
 73UsdGeom.Xformable(camera_prim1).AddTranslateOp().Set((0.0, 10.0, 20.0))
 74UsdGeom.Xformable(camera_prim1).AddRotateXYZOp().Set((-15.0, 0.0, 0.0))
 75
 76camera_prim2 = stage.DefinePrim("/World/Camera2", "Camera")
 77UsdGeom.Xformable(camera_prim2).AddTranslateOp().Set((-10.0, 15.0, 15.0))
 78UsdGeom.Xformable(camera_prim2).AddRotateXYZOp().Set((-45.0, 0.0, 45.0))
 79
 80# Create render products
 81rp1 = rep.create.render_product(str(camera_prim1.GetPrimPath()), resolution=(320, 320))
 82rp2 = rep.create.render_product(str(camera_prim2.GetPrimPath()), resolution=(640, 640))
 83rp3 = rep.create.render_product("/OmniverseKit_Persp", (1024, 1024))
 84
 85# Access the data through a custom writer
 86writer = rep.WriterRegistry.get("MyWriter")
 87writer.initialize(rgb=True)
 88writer.attach([rp1, rp2, rp3])
 89
 90# Access the data through annotators
 91rgb_annotators = []
 92for rp in [rp1, rp2, rp3]:
 93    rgb = rep.AnnotatorRegistry.get_annotator("rgb")
 94    rgb.attach(rp)
 95    rgb_annotators.append(rgb)
 96
 97# Create annotator output directory
 98file_path = os.path.join(os.getcwd(), "_out_mc_annot", "")
 99print(f"Writing annotator data to {file_path}")
100dir = os.path.dirname(file_path)
101os.makedirs(dir, exist_ok=True)
102
103# Data will be captured manually using step
104rep.orchestrator.set_capture_on_play(False)
105
106async def run_example_async():
107    for i in range(NUM_FRAMES):
108        # The step function provides new data to the annotators, triggers the randomizers and the writer
109        await rep.orchestrator.step_async(rt_subframes=4)
110        for j, rgb_annot in enumerate(rgb_annotators):
111            save_rgb(rgb_annot.get_data(), f"{dir}/rp{j}_step_{i}")
112
113
114asyncio.ensure_future(run_example_async())
Annotator and Custom Writer Data from Multiple Cameras
  1from isaacsim import SimulationApp
  2
  3simulation_app = SimulationApp(launch_config={"headless": False})
  4
  5import os
  6import omni.usd
  7import omni.kit
  8import omni.replicator.core as rep
  9import carb.settings
 10from omni.replicator.core import AnnotatorRegistry, Writer
 11from PIL import Image
 12from pxr import UsdGeom, Sdf
 13
 14NUM_FRAMES = 5
 15
 16# Save rgb image to file
 17def save_rgb(rgb_data, file_name):
 18    rgb_img = Image.fromarray(rgb_data).convert("RGBA")
 19    rgb_img.save(file_name + ".png")
 20
 21
 22# Randomize cube color every frame using a replicator randomizer
 23def cube_color_randomizer():
 24    cube_prims = rep.get.prims(path_pattern="Cube")
 25    with cube_prims:
 26        rep.randomizer.color(colors=rep.distribution.uniform((0, 0, 0), (1, 1, 1)))
 27    return cube_prims.node
 28
 29
 30# Access data through a custom replicator writer
 31class MyWriter(Writer):
 32    def __init__(self, rgb: bool = True):
 33        self._frame_id = 0
 34        self.annotators = []
 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_mc_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
 55# Create a new stage with a dome light
 56omni.usd.get_context().new_stage()
 57
 58# Set DLSS to Quality mode (2) for best SDG results (Options: 0 (Performance), 1 (Balanced), 2 (Quality), 3 (Auto)
 59carb.settings.get_settings().set("rtx/post/dlss/execMode", 2)
 60
 61stage = omni.usd.get_context().get_stage()
 62dome_light = stage.DefinePrim("/World/DomeLight", "DomeLight")
 63dome_light.CreateAttribute("inputs:intensity", Sdf.ValueTypeNames.Float).Set(900.0)
 64
 65# Create cube
 66cube_prim = stage.DefinePrim("/World/Cube", "Cube")
 67UsdGeom.Xformable(cube_prim).AddTranslateOp().Set((0.0, 5.0, 1.0))
 68
 69# Register cube color randomizer to trigger on every frame
 70rep.randomizer.register(cube_color_randomizer)
 71with rep.trigger.on_frame():
 72    rep.randomizer.cube_color_randomizer()
 73
 74# Create cameras
 75camera_prim1 = stage.DefinePrim("/World/Camera1", "Camera")
 76UsdGeom.Xformable(camera_prim1).AddTranslateOp().Set((0.0, 10.0, 20.0))
 77UsdGeom.Xformable(camera_prim1).AddRotateXYZOp().Set((-15.0, 0.0, 0.0))
 78
 79camera_prim2 = stage.DefinePrim("/World/Camera2", "Camera")
 80UsdGeom.Xformable(camera_prim2).AddTranslateOp().Set((-10.0, 15.0, 15.0))
 81UsdGeom.Xformable(camera_prim2).AddRotateXYZOp().Set((-45.0, 0.0, 45.0))
 82
 83# Create render products
 84rp1 = rep.create.render_product(str(camera_prim1.GetPrimPath()), resolution=(320, 320))
 85rp2 = rep.create.render_product(str(camera_prim2.GetPrimPath()), resolution=(640, 640))
 86rp3 = rep.create.render_product("/OmniverseKit_Persp", (1024, 1024))
 87
 88# Access the data through a custom writer
 89writer = rep.WriterRegistry.get("MyWriter")
 90writer.initialize(rgb=True)
 91writer.attach([rp1, rp2, rp3])
 92
 93# Access the data through annotators
 94rgb_annotators = []
 95for rp in [rp1, rp2, rp3]:
 96    rgb = rep.AnnotatorRegistry.get_annotator("rgb")
 97    rgb.attach(rp)
 98    rgb_annotators.append(rgb)
 99
100# Create annotator output directory
101file_path = os.path.join(os.getcwd(), "_out_mc_annot", "")
102print(f"Writing annotator data to {file_path}")
103dir = os.path.dirname(file_path)
104os.makedirs(dir, exist_ok=True)
105
106# Data will be captured manually using step
107rep.orchestrator.set_capture_on_play(False)
108
109for i in range(NUM_FRAMES):
110    # The step function provides new data to the annotators, triggers the randomizers and the writer
111    rep.orchestrator.step(rt_subframes=4)
112    for j, rgb_annot in enumerate(rgb_annotators):
113        save_rgb(rgb_annot.get_data(), f"{dir}/rp{j}_step_{i}")
114
115simulation_app.close()

Synthetic Data Access at Specific Simulation Timepoints#

Example on how to access synthetic data (RGB, semantic segmentation) from multiple cameras in a simulation scene at specific events using annotators or writers. The standalone example can also be run directly (on Windows use python.bat instead of python.sh):

./python.sh standalone_examples/api/isaacsim.replicator.examples/simulation_get_data.py
Synthetic Data Access at Specific Simulation Timepoints
 1import asyncio
 2import json
 3import os
 4
 5import carb.settings
 6import numpy as np
 7import omni
 8import omni.replicator.core as rep
 9from isaacsim.core.api import World
10from isaacsim.core.api.objects import DynamicCuboid
11from isaacsim.core.utils.semantics import add_labels
12from PIL import Image
13
14
15# Util function to save rgb annotator data
16def write_rgb_data(rgb_data, file_path):
17    rgb_img = Image.fromarray(rgb_data).convert("RGBA")
18    rgb_img.save(file_path + ".png")
19
20
21# Util function to save semantic segmentation annotator data
22def write_sem_data(sem_data, file_path):
23    id_to_labels = sem_data["info"]["idToLabels"]
24    with open(file_path + ".json", "w") as f:
25        json.dump(id_to_labels, f)
26    sem_image_data = sem_data["data"]
27    sem_img = Image.fromarray(sem_image_data).convert("RGBA")
28    sem_img.save(file_path + ".png")
29
30
31# Create a new stage with the default ground plane
32omni.usd.get_context().new_stage()
33
34# Setup the simulation world
35world = World()
36world.scene.add_default_ground_plane()
37
38# Setting capture on play to False will prevent the replicator from capturing data each frame
39carb.settings.get_settings().set("/omni/replicator/captureOnPlay", False)
40
41# Set DLSS to Quality mode (2) for best SDG results (Options: 0 (Performance), 1 (Balanced), 2 (Quality), 3 (Auto)
42carb.settings.get_settings().set("rtx/post/dlss/execMode", 2)
43
44# Create a camera and render product to collect the data from
45cam = rep.create.camera(position=(5, 5, 5), look_at=(0, 0, 0))
46rp = rep.create.render_product(cam, (512, 512))
47
48# Set the output directory for the data
49out_dir = os.path.join(os.getcwd(), "_out_sim_event")
50os.makedirs(out_dir, exist_ok=True)
51print(f"Outputting data to {out_dir}..")
52
53# Example of using a writer to save the data
54writer = rep.WriterRegistry.get("BasicWriter")
55writer.initialize(
56    output_dir=f"{out_dir}/writer", rgb=True, semantic_segmentation=True, colorize_semantic_segmentation=True
57)
58writer.attach(rp)
59
60# Run a preview to ensure the replicator graph is initialized
61rep.orchestrator.preview()
62
63# Example of accessing the data directly from annotators
64rgb_annot = rep.AnnotatorRegistry.get_annotator("rgb")
65rgb_annot.attach(rp)
66sem_annot = rep.AnnotatorRegistry.get_annotator("semantic_segmentation", init_params={"colorize": True})
67sem_annot.attach(rp)
68
69
70async def run_example_async():
71    await world.initialize_simulation_context_async()
72    await world.reset_async()
73
74    # Spawn and drop a few cubes, capture data when they stop moving
75    for i in range(5):
76        cuboid = world.scene.add(
77            DynamicCuboid(prim_path=f"/World/Cuboid_{i}", name=f"Cuboid_{i}", position=(0, 0, 10 + i))
78        )
79        add_labels(cuboid.prim, labels=["Cuboid"], instance_name="class")
80
81        for s in range(500):
82            await omni.kit.app.get_app().next_update_async()
83            vel = np.linalg.norm(cuboid.get_linear_velocity())
84            if vel < 0.1:
85                print(f"Cube_{i} stopped moving after {s} simulation steps, writing data..")
86                # Trigger the writer and update the annotators with new data
87                await rep.orchestrator.step_async(rt_subframes=4, delta_time=0.0, pause_timeline=False)
88                write_rgb_data(rgb_annot.get_data(), f"{out_dir}/Cube_{i}_step_{s}_rgb")
89                write_sem_data(sem_annot.get_data(), f"{out_dir}/Cube_{i}_step_{s}_sem")
90                break
91
92
93asyncio.ensure_future(run_example_async())
Synthetic Data Access at Specific Simulation Timepoints
 1from isaacsim import SimulationApp
 2
 3simulation_app = SimulationApp(launch_config={"renderer": "RayTracedLighting", "headless": False})
 4
 5import json
 6import os
 7
 8import carb.settings
 9import numpy as np
10import omni
11import omni.replicator.core as rep
12from isaacsim.core.api import World
13from isaacsim.core.api.objects import DynamicCuboid
14from isaacsim.core.utils.semantics import add_labels
15from PIL import Image
16
17
18# Util function to save rgb annotator data
19def write_rgb_data(rgb_data, file_path):
20    rgb_img = Image.fromarray(rgb_data).convert("RGBA")
21    rgb_img.save(file_path + ".png")
22
23
24# Util function to save semantic segmentation annotator data
25def write_sem_data(sem_data, file_path):
26    id_to_labels = sem_data["info"]["idToLabels"]
27    with open(file_path + ".json", "w") as f:
28        json.dump(id_to_labels, f)
29    sem_image_data = sem_data["data"]
30    sem_img = Image.fromarray(sem_image_data).convert("RGBA")
31    sem_img.save(file_path + ".png")
32
33
34# Create a new stage with the default ground plane
35omni.usd.get_context().new_stage()
36
37# Setup the simulation world
38world = World()
39world.scene.add_default_ground_plane()
40world.reset()
41
42# Setting capture on play to False will prevent the replicator from capturing data each frame
43carb.settings.get_settings().set("/omni/replicator/captureOnPlay", False)
44
45# Set DLSS to Quality mode (2) for best SDG results (Options: 0 (Performance), 1 (Balanced), 2 (Quality), 3 (Auto)
46carb.settings.get_settings().set("rtx/post/dlss/execMode", 2)
47
48# Create a camera and render product to collect the data from
49cam = rep.create.camera(position=(5, 5, 5), look_at=(0, 0, 0))
50rp = rep.create.render_product(cam, (512, 512))
51
52# Set the output directory for the data
53out_dir = os.path.join(os.getcwd(), "_out_sim_event")
54os.makedirs(out_dir, exist_ok=True)
55print(f"Outputting data to {out_dir}..")
56
57# Example of using a writer to save the data
58writer = rep.WriterRegistry.get("BasicWriter")
59writer.initialize(
60    output_dir=f"{out_dir}/writer", rgb=True, semantic_segmentation=True, colorize_semantic_segmentation=True
61)
62writer.attach(rp)
63
64# Run a preview to ensure the replicator graph is initialized
65rep.orchestrator.preview()
66
67# Example of accessing the data directly from annotators
68rgb_annot = rep.AnnotatorRegistry.get_annotator("rgb")
69rgb_annot.attach(rp)
70sem_annot = rep.AnnotatorRegistry.get_annotator("semantic_segmentation", init_params={"colorize": True})
71sem_annot.attach(rp)
72
73# Spawn and drop a few cubes, capture data when they stop moving
74for i in range(5):
75    cuboid = world.scene.add(DynamicCuboid(prim_path=f"/World/Cuboid_{i}", name=f"Cuboid_{i}", position=(0, 0, 10 + i)))
76    add_labels(cuboid.prim, labels=["Cuboid"], instance_name="class")
77
78    for s in range(500):
79        world.step(render=False)
80        vel = np.linalg.norm(cuboid.get_linear_velocity())
81        if vel < 0.1:
82            print(f"Cube_{i} stopped moving after {s} simulation steps, writing data..")
83            # Trigger the writer and update the annotators with new data
84            rep.orchestrator.step(rt_subframes=4, delta_time=0.0, pause_timeline=False)
85            write_rgb_data(rgb_annot.get_data(), f"{out_dir}/Cube_{i}_step_{s}_rgb")
86            write_sem_data(sem_annot.get_data(), f"{out_dir}/Cube_{i}_step_{s}_sem")
87            break
88
89simulation_app.close()

Custom Event Randomization and Writing#

The following example showcases the use of custom events to trigger randomizations and data writing at various times throughout the simulation. The standalone example can also be run directly (on Windows use python.bat instead of python.sh):

./python.sh standalone_examples/api/isaacsim.replicator.examples/custom_event_and_write.py
Custom Event Randomization and Writing
 1import asyncio
 2import os
 3
 4import carb.settings
 5import omni.replicator.core as rep
 6import omni.usd
 7
 8omni.usd.get_context().new_stage()
 9# Set DLSS to Quality mode (2) for best SDG results , options: 0 (Performance), 1 (Balanced), 2 (Quality), 3 (Auto)
10carb.settings.get_settings().set("rtx/post/dlss/execMode", 2)
11distance_light = rep.create.light(rotation=(315, 0, 0), intensity=4000, light_type="distant")
12
13large_cube = rep.create.cube(scale=1.25, position=(1, 1, 0))
14small_cube = rep.create.cube(scale=0.75, position=(-1, -1, 0))
15large_cube_prim = large_cube.get_output_prims()["prims"][0]
16small_cube_prim = small_cube.get_output_prims()["prims"][0]
17
18rp = rep.create.render_product("/OmniverseKit_Persp", (512, 512))
19writer = rep.WriterRegistry.get("BasicWriter")
20out_dir = os.path.join(os.getcwd(), "_out_custom_event")
21print(f"Writing data to {out_dir}")
22writer.initialize(output_dir=out_dir, rgb=True)
23writer.attach(rp)
24
25with rep.trigger.on_custom_event(event_name="randomize_large_cube"):
26    with large_cube:
27        rep.randomizer.rotation()
28
29with rep.trigger.on_custom_event(event_name="randomize_small_cube"):
30    with small_cube:
31        rep.randomizer.rotation()
32
33
34async def run_example_async():
35    print(f"Randomizing small cube")
36    rep.utils.send_og_event(event_name="randomize_small_cube")
37    print("Capturing frame")
38    await rep.orchestrator.step_async(rt_subframes=8)
39
40    print("Moving small cube")
41    small_cube_prim.GetAttribute("xformOp:translate").Set((-2, -2, 0))
42    print("Capturing frame")
43    await rep.orchestrator.step_async(rt_subframes=8)
44
45    print(f"Randomizing large cube")
46    rep.utils.send_og_event(event_name="randomize_large_cube")
47    print("Capturing frame")
48    await rep.orchestrator.step_async(rt_subframes=8)
49
50    print("Moving large cube")
51    large_cube_prim.GetAttribute("xformOp:translate").Set((2, 2, 0))
52    print("Capturing frame")
53    await rep.orchestrator.step_async(rt_subframes=8)
54
55    # Wait until all the data is saved to disk
56    await rep.orchestrator.wait_until_complete_async()
57
58
59asyncio.ensure_future(run_example_async())
Custom Event Randomization and Writing
 1from isaacsim import SimulationApp
 2
 3simulation_app = SimulationApp(launch_config={"headless": False})
 4
 5import os
 6
 7import carb.settings
 8import omni.replicator.core as rep
 9import omni.usd
10
11omni.usd.get_context().new_stage()
12# Set DLSS to Quality mode (2) for best SDG results , options: 0 (Performance), 1 (Balanced), 2 (Quality), 3 (Auto)
13carb.settings.get_settings().set("rtx/post/dlss/execMode", 2)
14distance_light = rep.create.light(rotation=(315, 0, 0), intensity=4000, light_type="distant")
15
16large_cube = rep.create.cube(scale=1.25, position=(1, 1, 0))
17small_cube = rep.create.cube(scale=0.75, position=(-1, -1, 0))
18large_cube_prim = large_cube.get_output_prims()["prims"][0]
19small_cube_prim = small_cube.get_output_prims()["prims"][0]
20
21rp = rep.create.render_product("/OmniverseKit_Persp", (512, 512))
22writer = rep.WriterRegistry.get("BasicWriter")
23out_dir = os.path.join(os.getcwd(), "_out_custom_event")
24print(f"Writing data to {out_dir}")
25writer.initialize(output_dir=out_dir, rgb=True)
26writer.attach(rp)
27
28with rep.trigger.on_custom_event(event_name="randomize_large_cube"):
29    with large_cube:
30        rep.randomizer.rotation()
31
32with rep.trigger.on_custom_event(event_name="randomize_small_cube"):
33    with small_cube:
34        rep.randomizer.rotation()
35
36
37def run_example():
38    print(f"Randomizing small cube")
39    rep.utils.send_og_event(event_name="randomize_small_cube")
40    print("Capturing frame")
41    rep.orchestrator.step(rt_subframes=8)
42
43    print("Moving small cube")
44    small_cube_prim.GetAttribute("xformOp:translate").Set((-2, -2, 0))
45    print("Capturing frame")
46    rep.orchestrator.step(rt_subframes=8)
47
48    print(f"Randomizing large cube")
49    rep.utils.send_og_event(event_name="randomize_large_cube")
50    print("Capturing frame")
51    rep.orchestrator.step(rt_subframes=8)
52
53    print("Moving large cube")
54    large_cube_prim.GetAttribute("xformOp:translate").Set((2, 2, 0))
55    print("Capturing frame")
56    rep.orchestrator.step(rt_subframes=8)
57
58    # Wait until all the data is saved to disk
59    rep.orchestrator.wait_until_complete()
60
61
62run_example()
63
64simulation_app.close()

Motion Blur#

This example demonstrates how to capture motion blur data using RTX Real-Time and RTX Interactive (Path Tracing) rendering modes. For the RTX - Real-Time mode, refer to motion blur parameters. For the RTX – Interactive (Path Tracing) mode, motion blur is achieved by rendering multiple subframes (/omni/replicator/pathTracedMotionBlurSubSamples) and combining them to create the effect.

The example uses animated and physics-enabled assets with synchronized motion. Keyframe animated assets can be advanced at any custom delta time due to their interpolated motion, whereas physics-enabled assets require a custom physics FPS to ensure motion samples at any custom delta time. The example showcases how to compute the target physics FPS, change it if needed, and restore the original physics FPS after capturing the motion blur.

The standalone example can also be run directly (on Windows use python.bat instead of python.sh):

./python.sh standalone_examples/api/isaacsim.replicator.examples/motion_blur.py
Motion Blur
  1import asyncio
  2import os
  3
  4import carb.settings
  5import omni.kit.app
  6import omni.replicator.core as rep
  7import omni.timeline
  8import omni.usd
  9from isaacsim.storage.native import get_assets_root_path
 10from pxr import PhysxSchema, Sdf, UsdGeom, UsdPhysics
 11
 12# Paths to the animated and physics-ready assets
 13PHYSICS_ASSET_URL = "/Isaac/Props/YCB/Axis_Aligned_Physics/003_cracker_box.usd"
 14ANIM_ASSET_URL = "/Isaac/Props/YCB/Axis_Aligned/003_cracker_box.usd"
 15
 16# -z velocities and start locations of the animated (left side) and physics (right side) assets (stage units/s)
 17ASSET_VELOCITIES = [0, 5, 10]
 18ASSET_X_MIRRORED_LOCATIONS = [(0.5, 0, 0.3), (0.3, 0, 0.3), (0.1, 0, 0.3)]
 19
 20# Used to calculate how many frames to animate the assets to maintain the same velocity as the physics assets
 21ANIMATION_DURATION = 10
 22
 23# Create a new stage with animated and physics-enabled assets with synchronized motion
 24def setup_stage():
 25    # Create new stage
 26    omni.usd.get_context().new_stage()
 27    stage = omni.usd.get_context().get_stage()
 28    timeline = omni.timeline.get_timeline_interface()
 29    timeline.set_end_time(ANIMATION_DURATION)
 30
 31    # Create lights
 32    dome_light = stage.DefinePrim("/World/DomeLight", "DomeLight")
 33    dome_light.CreateAttribute("inputs:intensity", Sdf.ValueTypeNames.Float).Set(100.0)
 34    distant_light = stage.DefinePrim("/World/DistantLight", "DistantLight")
 35    if not distant_light.GetAttribute("xformOp:rotateXYZ"):
 36        UsdGeom.Xformable(distant_light).AddRotateXYZOp()
 37    distant_light.GetAttribute("xformOp:rotateXYZ").Set((-75, 0, 0))
 38    distant_light.CreateAttribute("inputs:intensity", Sdf.ValueTypeNames.Float).Set(2500)
 39
 40    # Setup the physics assets with gravity disabled and the requested velocity
 41    assets_root_path = get_assets_root_path()
 42    physics_asset_url = assets_root_path + PHYSICS_ASSET_URL
 43    for loc, vel in zip(ASSET_X_MIRRORED_LOCATIONS, ASSET_VELOCITIES):
 44        prim = stage.DefinePrim(f"/World/physics_asset_{int(abs(vel))}", "Xform")
 45        prim.GetReferences().AddReference(physics_asset_url)
 46        if not prim.GetAttribute("xformOp:translate"):
 47            UsdGeom.Xformable(prim).AddTranslateOp()
 48        prim.GetAttribute("xformOp:translate").Set(loc)
 49        prim.GetAttribute("physxRigidBody:disableGravity").Set(True)
 50        prim.GetAttribute("physxRigidBody:angularDamping").Set(0.0)
 51        prim.GetAttribute("physxRigidBody:linearDamping").Set(0.0)
 52        prim.GetAttribute("physics:velocity").Set((0, 0, -vel))
 53
 54    # Setup animated assets maintaining the same velocity as the physics assets
 55    anim_asset_url = assets_root_path + ANIM_ASSET_URL
 56    for loc, vel in zip(ASSET_X_MIRRORED_LOCATIONS, ASSET_VELOCITIES):
 57        start_loc = (-loc[0], loc[1], loc[2])
 58        prim = stage.DefinePrim(f"/World/anim_asset_{int(abs(vel))}", "Xform")
 59        prim.GetReferences().AddReference(anim_asset_url)
 60        if not prim.GetAttribute("xformOp:translate"):
 61            UsdGeom.Xformable(prim).AddTranslateOp()
 62        anim_distance = vel * ANIMATION_DURATION
 63        end_loc = (start_loc[0], start_loc[1], start_loc[2] - anim_distance)
 64        end_keyframe = timeline.get_time_codes_per_seconds() * ANIMATION_DURATION
 65        # Timesampled keyframe (animated) translation
 66        prim.GetAttribute("xformOp:translate").Set(start_loc, time=0)
 67        prim.GetAttribute("xformOp:translate").Set(end_loc, time=end_keyframe)
 68
 69
 70# Capture motion blur frames with the given delta time step and render mode
 71async def run_motion_blur_example_async(
 72    num_frames=3, custom_delta_time=None, use_path_tracing=True, pt_subsamples=8, pt_spp=64
 73):
 74    # Create a new stage with the assets
 75    setup_stage()
 76    stage = omni.usd.get_context().get_stage()
 77
 78    # Set replicator settings (capture only on request and enable motion blur)
 79    carb.settings.get_settings().set("/omni/replicator/captureOnPlay", False)
 80    carb.settings.get_settings().set("/omni/replicator/captureMotionBlur", True)
 81
 82    # Set DLSS to Quality mode (2) for best SDG results (Options: 0 (Performance), 1 (Balanced), 2 (Quality), 3 (Auto)
 83    carb.settings.get_settings().set("rtx/post/dlss/execMode", 2)
 84
 85    # Set motion blur settings based on the render mode
 86    if use_path_tracing:
 87        print(f"[MotionBlur] Setting PathTracing render mode motion blur settings")
 88        carb.settings.get_settings().set("/rtx/rendermode", "PathTracing")
 89        # (int): Total number of samples for each rendered pixel, per frame.
 90        carb.settings.get_settings().set("/rtx/pathtracing/spp", pt_spp)
 91        # (int): Maximum number of samples to accumulate per pixel. When this count is reached the rendering stops until a scene or setting change is detected, restarting the rendering process. Set to 0 to remove this limit.
 92        carb.settings.get_settings().set("/rtx/pathtracing/totalSpp", pt_spp)
 93        carb.settings.get_settings().set("/rtx/pathtracing/optixDenoiser/enabled", 0)
 94        # Number of sub samples to render if in PathTracing render mode and motion blur is enabled.
 95        carb.settings.get_settings().set("/omni/replicator/pathTracedMotionBlurSubSamples", pt_subsamples)
 96    else:
 97        print(f"[MotionBlur] Setting RayTracedLighting render mode motion blur settings")
 98        carb.settings.get_settings().set("/rtx/rendermode", "RayTracedLighting")
 99        # 0: Disabled, 1: TAA, 2: FXAA, 3: DLSS, 4:RTXAA
100        carb.settings.get_settings().set("/rtx/post/aa/op", 2)
101        # (float): The fraction of the largest screen dimension to use as the maximum motion blur diameter.
102        carb.settings.get_settings().set("/rtx/post/motionblur/maxBlurDiameterFraction", 0.02)
103        # (float): Exposure time fraction in frames (1.0 = one frame duration) to sample.
104        carb.settings.get_settings().set("/rtx/post/motionblur/exposureFraction", 1.0)
105        # (int): Number of samples to use in the filter. A higher number improves quality at the cost of performance.
106        carb.settings.get_settings().set("/rtx/post/motionblur/numSamples", 8)
107
108    # Setup camera and writer
109    camera = rep.create.camera(position=(0, 1.5, 0), look_at=(0, 0, 0), name="MotionBlurCam")
110    render_product = rep.create.render_product(camera, (1280, 720))
111    basic_writer = rep.WriterRegistry.get("BasicWriter")
112    delta_time_str = "None" if custom_delta_time is None else f"{custom_delta_time:.4f}"
113    render_mode_str = f"pt_subsamples_{pt_subsamples}_spp_{pt_spp}" if use_path_tracing else "rt"
114    output_directory = os.path.join(os.getcwd(), f"_out_motion_blur_dt_{delta_time_str}_{render_mode_str}")
115    print(f"[MotionBlur] Output directory: {output_directory}")
116    basic_writer.initialize(output_dir=output_directory, rgb=True)
117    basic_writer.attach(render_product)
118
119    # Run a few updates to make sure all materials are fully loaded for capture
120    for _ in range(50):
121        await omni.kit.app.get_app().next_update_async()
122
123    # Use the physics scene to modify the physics FPS (if needed) to guarantee motion samples at any custom delta time
124    physx_scene = None
125    for prim in stage.Traverse():
126        if prim.IsA(UsdPhysics.Scene):
127            physx_scene = PhysxSchema.PhysxSceneAPI.Apply(prim)
128            break
129    if physx_scene is None:
130        print(f"[MotionBlur] Creating a new PhysicsScene")
131        physics_scene = UsdPhysics.Scene.Define(stage, "/PhysicsScene")
132        physx_scene = PhysxSchema.PhysxSceneAPI.Apply(stage.GetPrimAtPath("/PhysicsScene"))
133
134    # Check the target physics depending on the custom delta time and the render mode
135    target_physics_fps = stage.GetTimeCodesPerSecond() if custom_delta_time is None else 1 / custom_delta_time
136    if use_path_tracing:
137        target_physics_fps *= pt_subsamples
138
139    # Check if the physics FPS needs to be increased to match the custom delta time
140    orig_physics_fps = physx_scene.GetTimeStepsPerSecondAttr().Get()
141    if target_physics_fps > orig_physics_fps:
142        print(f"[MotionBlur] Changing physics FPS from {orig_physics_fps} to {target_physics_fps}")
143        physx_scene.GetTimeStepsPerSecondAttr().Set(target_physics_fps)
144
145    # Start the timeline for physics updates in the step function
146    timeline = omni.timeline.get_timeline_interface()
147    timeline.play()
148
149    # Capture frames
150    for i in range(num_frames):
151        print(f"[MotionBlur] \tCapturing frame {i}")
152        await rep.orchestrator.step_async(delta_time=custom_delta_time)
153
154    # Restore the original physics FPS
155    if target_physics_fps > orig_physics_fps:
156        print(f"[MotionBlur] Restoring physics FPS from {target_physics_fps} to {orig_physics_fps}")
157        physx_scene.GetTimeStepsPerSecondAttr().Set(orig_physics_fps)
158
159    # Switch back to the raytracing render mode
160    if use_path_tracing:
161        print(f"[MotionBlur] Restoring render mode to RayTracedLighting")
162        carb.settings.get_settings().set("/rtx/rendermode", "RayTracedLighting")
163
164    # Wait until all the data is saved to disk
165    await rep.orchestrator.wait_until_complete_async()
166
167
168async def run_motion_blur_examples_async():
169    motion_blur_step_duration = [None, 1 / 30, 1 / 60, 1 / 240]
170    for custom_delta_time in motion_blur_step_duration:
171        # RayTracing examples
172        await run_motion_blur_example_async(custom_delta_time=custom_delta_time, use_path_tracing=False)
173        # PathTracing examples
174        spps = [32, 128]
175        motion_blur_sub_samples = [4, 16]
176        for motion_blur_sub_sample in motion_blur_sub_samples:
177            for spp in spps:
178                await run_motion_blur_example_async(
179                    custom_delta_time=custom_delta_time,
180                    use_path_tracing=True,
181                    pt_subsamples=motion_blur_sub_sample,
182                    pt_spp=spp,
183                )
184
185
186asyncio.ensure_future(run_motion_blur_examples_async())
Motion Blur
  1from isaacsim import SimulationApp
  2
  3simulation_app = SimulationApp({"headless": False})
  4
  5import os
  6
  7import carb.settings
  8import omni.kit.app
  9import omni.replicator.core as rep
 10import omni.timeline
 11import omni.usd
 12from isaacsim.storage.native import get_assets_root_path
 13from pxr import PhysxSchema, Sdf, UsdGeom, UsdPhysics
 14
 15# Paths to the animated and physics-ready assets
 16PHYSICS_ASSET_URL = "/Isaac/Props/YCB/Axis_Aligned_Physics/003_cracker_box.usd"
 17ANIM_ASSET_URL = "/Isaac/Props/YCB/Axis_Aligned/003_cracker_box.usd"
 18
 19# -z velocities and start locations of the animated (left side) and physics (right side) assets (stage units/s)
 20ASSET_VELOCITIES = [0, 5, 10]
 21ASSET_X_MIRRORED_LOCATIONS = [(0.5, 0, 0.3), (0.3, 0, 0.3), (0.1, 0, 0.3)]
 22
 23# Used to calculate how many frames to animate the assets to maintain the same velocity as the physics assets
 24ANIMATION_DURATION = 10
 25
 26# Create a new stage with animated and physics-enabled assets with synchronized motion
 27def setup_stage():
 28    # Create new stage
 29    omni.usd.get_context().new_stage()
 30    stage = omni.usd.get_context().get_stage()
 31    timeline = omni.timeline.get_timeline_interface()
 32    timeline.set_end_time(ANIMATION_DURATION)
 33
 34    # Create lights
 35    dome_light = stage.DefinePrim("/World/DomeLight", "DomeLight")
 36    dome_light.CreateAttribute("inputs:intensity", Sdf.ValueTypeNames.Float).Set(100.0)
 37    distant_light = stage.DefinePrim("/World/DistantLight", "DistantLight")
 38    if not distant_light.GetAttribute("xformOp:rotateXYZ"):
 39        UsdGeom.Xformable(distant_light).AddRotateXYZOp()
 40    distant_light.GetAttribute("xformOp:rotateXYZ").Set((-75, 0, 0))
 41    distant_light.CreateAttribute("inputs:intensity", Sdf.ValueTypeNames.Float).Set(2500)
 42
 43    # Setup the physics assets with gravity disabled and the requested velocity
 44    assets_root_path = get_assets_root_path()
 45    physics_asset_url = assets_root_path + PHYSICS_ASSET_URL
 46    for loc, vel in zip(ASSET_X_MIRRORED_LOCATIONS, ASSET_VELOCITIES):
 47        prim = stage.DefinePrim(f"/World/physics_asset_{int(abs(vel))}", "Xform")
 48        prim.GetReferences().AddReference(physics_asset_url)
 49        if not prim.GetAttribute("xformOp:translate"):
 50            UsdGeom.Xformable(prim).AddTranslateOp()
 51        prim.GetAttribute("xformOp:translate").Set(loc)
 52        prim.GetAttribute("physxRigidBody:disableGravity").Set(True)
 53        prim.GetAttribute("physxRigidBody:angularDamping").Set(0.0)
 54        prim.GetAttribute("physxRigidBody:linearDamping").Set(0.0)
 55        prim.GetAttribute("physics:velocity").Set((0, 0, -vel))
 56
 57    # Setup animated assets maintaining the same velocity as the physics assets
 58    anim_asset_url = assets_root_path + ANIM_ASSET_URL
 59    for loc, vel in zip(ASSET_X_MIRRORED_LOCATIONS, ASSET_VELOCITIES):
 60        start_loc = (-loc[0], loc[1], loc[2])
 61        prim = stage.DefinePrim(f"/World/anim_asset_{int(abs(vel))}", "Xform")
 62        prim.GetReferences().AddReference(anim_asset_url)
 63        if not prim.GetAttribute("xformOp:translate"):
 64            UsdGeom.Xformable(prim).AddTranslateOp()
 65        anim_distance = vel * ANIMATION_DURATION
 66        end_loc = (start_loc[0], start_loc[1], start_loc[2] - anim_distance)
 67        end_keyframe = timeline.get_time_codes_per_seconds() * ANIMATION_DURATION
 68        # Timesampled keyframe (animated) translation
 69        prim.GetAttribute("xformOp:translate").Set(start_loc, time=0)
 70        prim.GetAttribute("xformOp:translate").Set(end_loc, time=end_keyframe)
 71
 72
 73# Capture motion blur frames with the given delta time step and render mode
 74def run_motion_blur_example(num_frames=3, custom_delta_time=None, use_path_tracing=True, pt_subsamples=8, pt_spp=64):
 75    # Create a new stage with the assets
 76    setup_stage()
 77    stage = omni.usd.get_context().get_stage()
 78
 79    # Set replicator settings (capture only on request and enable motion blur)
 80    carb.settings.get_settings().set("/omni/replicator/captureOnPlay", False)
 81    carb.settings.get_settings().set("/omni/replicator/captureMotionBlur", True)
 82
 83    # Set DLSS to Quality mode (2) for best SDG results (Options: 0 (Performance), 1 (Balanced), 2 (Quality), 3 (Auto)
 84    carb.settings.get_settings().set("rtx/post/dlss/execMode", 2)
 85
 86    # Set motion blur settings based on the render mode
 87    if use_path_tracing:
 88        print(f"[MotionBlur] Setting PathTracing render mode motion blur settings")
 89        carb.settings.get_settings().set("/rtx/rendermode", "PathTracing")
 90        # (int): Total number of samples for each rendered pixel, per frame.
 91        carb.settings.get_settings().set("/rtx/pathtracing/spp", pt_spp)
 92        # (int): Maximum number of samples to accumulate per pixel. When this count is reached the rendering stops until a scene or setting change is detected, restarting the rendering process. Set to 0 to remove this limit.
 93        carb.settings.get_settings().set("/rtx/pathtracing/totalSpp", pt_spp)
 94        carb.settings.get_settings().set("/rtx/pathtracing/optixDenoiser/enabled", 0)
 95        # Number of sub samples to render if in PathTracing render mode and motion blur is enabled.
 96        carb.settings.get_settings().set("/omni/replicator/pathTracedMotionBlurSubSamples", pt_subsamples)
 97    else:
 98        print(f"[MotionBlur] Setting RayTracedLighting render mode motion blur settings")
 99        carb.settings.get_settings().set("/rtx/rendermode", "RayTracedLighting")
100        # 0: Disabled, 1: TAA, 2: FXAA, 3: DLSS, 4:RTXAA
101        carb.settings.get_settings().set("/rtx/post/aa/op", 2)
102        # (float): The fraction of the largest screen dimension to use as the maximum motion blur diameter.
103        carb.settings.get_settings().set("/rtx/post/motionblur/maxBlurDiameterFraction", 0.02)
104        # (float): Exposure time fraction in frames (1.0 = one frame duration) to sample.
105        carb.settings.get_settings().set("/rtx/post/motionblur/exposureFraction", 1.0)
106        # (int): Number of samples to use in the filter. A higher number improves quality at the cost of performance.
107        carb.settings.get_settings().set("/rtx/post/motionblur/numSamples", 8)
108
109    # Setup camera and writer
110    camera = rep.create.camera(position=(0, 1.5, 0), look_at=(0, 0, 0), name="MotionBlurCam")
111    render_product = rep.create.render_product(camera, (1280, 720))
112    basic_writer = rep.WriterRegistry.get("BasicWriter")
113    delta_time_str = "None" if custom_delta_time is None else f"{custom_delta_time:.4f}"
114    render_mode_str = f"pt_subsamples_{pt_subsamples}_spp_{pt_spp}" if use_path_tracing else "rt"
115    output_directory = os.path.join(os.getcwd(), f"_out_motion_blur_dt_{delta_time_str}_{render_mode_str}")
116    print(f"[MotionBlur] Output directory: {output_directory}")
117    basic_writer.initialize(output_dir=output_directory, rgb=True)
118    basic_writer.attach(render_product)
119
120    # Run a few updates to make sure all materials are fully loaded for capture
121    for _ in range(50):
122        simulation_app.update()
123
124    # Use the physics scene to modify the physics FPS (if needed) to guarantee motion samples at any custom delta time
125    physx_scene = None
126    for prim in stage.Traverse():
127        if prim.IsA(UsdPhysics.Scene):
128            physx_scene = PhysxSchema.PhysxSceneAPI.Apply(prim)
129            break
130    if physx_scene is None:
131        print(f"[MotionBlur] Creating a new PhysicsScene")
132        physics_scene = UsdPhysics.Scene.Define(stage, "/PhysicsScene")
133        physx_scene = PhysxSchema.PhysxSceneAPI.Apply(stage.GetPrimAtPath("/PhysicsScene"))
134
135    # Check the target physics depending on the custom delta time and the render mode
136    target_physics_fps = stage.GetTimeCodesPerSecond() if custom_delta_time is None else 1 / custom_delta_time
137    if use_path_tracing:
138        target_physics_fps *= pt_subsamples
139
140    # Check if the physics FPS needs to be increased to match the custom delta time
141    orig_physics_fps = physx_scene.GetTimeStepsPerSecondAttr().Get()
142    if target_physics_fps > orig_physics_fps:
143        print(f"[MotionBlur] Changing physics FPS from {orig_physics_fps} to {target_physics_fps}")
144        physx_scene.GetTimeStepsPerSecondAttr().Set(target_physics_fps)
145
146    # Start the timeline for physics updates in the step function
147    timeline = omni.timeline.get_timeline_interface()
148    timeline.play()
149
150    # Capture frames
151    for i in range(num_frames):
152        print(f"[MotionBlur] \tCapturing frame {i}")
153        rep.orchestrator.step(delta_time=custom_delta_time)
154
155    # Restore the original physics FPS
156    if target_physics_fps > orig_physics_fps:
157        print(f"[MotionBlur] Restoring physics FPS from {target_physics_fps} to {orig_physics_fps}")
158        physx_scene.GetTimeStepsPerSecondAttr().Set(orig_physics_fps)
159
160    # Switch back to the raytracing render mode
161    if use_path_tracing:
162        print(f"[MotionBlur] Restoring render mode to RayTracedLighting")
163        carb.settings.get_settings().set("/rtx/rendermode", "RayTracedLighting")
164
165    # Wait until all the data is saved to disk
166    rep.orchestrator.wait_until_complete()
167
168
169def run_motion_blur_examples():
170    motion_blur_step_duration = [None, 1 / 30, 1 / 60, 1 / 240]
171    for custom_delta_time in motion_blur_step_duration:
172        # RayTracing examples
173        run_motion_blur_example(custom_delta_time=custom_delta_time, use_path_tracing=False)
174        # PathTracing examples
175        spps = [32, 128]
176        motion_blur_sub_samples = [4, 16]
177        for motion_blur_sub_sample in motion_blur_sub_samples:
178            for spp in spps:
179                run_motion_blur_example(
180                    custom_delta_time=custom_delta_time,
181                    use_path_tracing=True,
182                    pt_subsamples=motion_blur_sub_sample,
183                    pt_spp=spp,
184                )
185
186
187run_motion_blur_examples()
188
189simulation_app.close()

Subscribers and Events at Custom FPS#

Examples of subscribing to various events (such as stage, physics, and render/app), setting custom update rates, and adjusting various related settings. The standalone example can also be run directly (on Windows use python.bat instead of python.sh):

./python.sh standalone_examples/api/isaacsim.replicator.examples/subscribers_and_events.py
Subscribers and Events at Custom FPS
  1import asyncio
  2import time
  3
  4import carb.eventdispatcher
  5import carb.settings
  6import omni.kit.app
  7import omni.physx
  8import omni.timeline
  9import omni.usd
 10from pxr import PhysxSchema, UsdPhysics
 11
 12# TIMELINE / STAGE
 13USE_CUSTOM_TIMELINE_SETTINGS = True
 14USE_FIXED_TIME_STEPPING = True
 15PLAY_EVERY_FRAME = True
 16PLAY_DELAY_COMPENSATION = 0.0
 17SUBSAMPLE_RATE = 1
 18STAGE_FPS = 30.0
 19
 20# PHYSX
 21USE_CUSTOM_PHYSX_FPS = False
 22PHYSX_FPS = 60.0
 23MIN_SIM_FPS = 30
 24
 25# Simulations can also be enabled/disabled at runtime
 26DISABLE_SIMULATIONS = False
 27
 28# APP / RENDER
 29LIMIT_APP_FPS = False
 30APP_FPS = 120
 31
 32# Number of app updates to run while collecting events
 33NUM_APP_UPDATES = 100
 34
 35# Print the captured events
 36VERBOSE = False
 37
 38async def run_subscribers_and_events_async():
 39    def on_timeline_event(event: omni.timeline.TimelineEventType):
 40        nonlocal timeline_events
 41        if event.type == omni.timeline.TimelineEventType.CURRENT_TIME_TICKED.value:
 42            timeline_events.append(event.payload)
 43            if VERBOSE:
 44                print(f"  [timeline][{len(timeline_events)}] {event.payload}")
 45
 46    def on_physics_step(dt: float):
 47        nonlocal physx_events
 48        physx_events.append(dt)
 49        if VERBOSE:
 50            print(f"  [physics][{len(physx_events)}] dt={dt}")
 51
 52    def on_stage_render_event(event: carb.eventdispatcher.Event):
 53        nonlocal stage_render_events
 54        stage_render_events.append(event.event_name)
 55        if VERBOSE:
 56            print(f"  [stage render][{len(stage_render_events)}] {event.event_name}")
 57
 58    def on_app_update(event: carb.eventdispatcher.Event):
 59        nonlocal app_update_events
 60        app_update_events.append(event.event_name)
 61        if VERBOSE:
 62            print(f"  [app update][{len(app_update_events)}] {event.event_name}")
 63
 64    stage = omni.usd.get_context().get_stage()
 65    timeline = omni.timeline.get_timeline_interface()
 66
 67    if USE_CUSTOM_TIMELINE_SETTINGS:
 68        # Ideal to make simulation and animation synchronized.
 69        # Default: True in editor, False in standalone.
 70        # NOTE:
 71        # - It may limit the frame rate (see 'timeline.set_play_every_frame') such that the elapsed wall clock time matches the frame's delta time.
 72        # - If the app runs slower than this, animation playback may slow down (see 'CompensatePlayDelayInSecs').
 73        # - For performance benchmarks, turn this off or set a very high target in `timeline.set_target_framerate`
 74        carb.settings.get_settings().set("/app/player/useFixedTimeStepping", USE_FIXED_TIME_STEPPING)
 75
 76        # This compensates for frames that require more computation time than the frame's fixed delta time, by temporarily speeding up playback.
 77        # The parameter represents the length of these "faster" playback periods, which means that it must be larger than the fixed frame time to take effect.
 78        # Default: 0.0
 79        # NOTE:
 80        # - only effective if `useFixedTimeStepping` is set to True
 81        # - setting a large value results in long fast playback after a huge lag spike
 82        carb.settings.get_settings().set("/app/player/CompensatePlayDelayInSecs", PLAY_DELAY_COMPENSATION)
 83
 84        # If set to True, no frames are skipped and in every frame time advances by `1 / TimeCodesPerSecond`.
 85        # Default: False
 86        # NOTE:
 87        # - only effective if `useFixedTimeStepping` is set to True
 88        # - simulation is usually faster than real-time and processing is only limited by the frame rate of the runloop
 89        # - useful for recording
 90        # - same as `carb.settings.get_settings().set("/app/player/useFastMode", PLAY_EVERY_FRAME)`
 91        timeline.set_play_every_frame(PLAY_EVERY_FRAME)
 92
 93        # Timeline sub-stepping, i.e. how many times updates are called (update events are dispatched) each frame.
 94        # Default: 1
 95        # NOTE: same as `carb.settings.get_settings().set("/app/player/timelineSubsampleRate", SUBSAMPLE_RATE)`
 96        timeline.set_ticks_per_frame(SUBSAMPLE_RATE)
 97
 98        # Time codes per second for the stage
 99        # NOTE: same as `stage.SetTimeCodesPerSecond(STAGE_FPS)` and `carb.settings.get_settings().set("/app/stage/timeCodesPerSecond", STAGE_FPS)`
100        timeline.set_time_codes_per_second(STAGE_FPS)
101
102    # Create a PhysX scene to set the physics time step
103    if USE_CUSTOM_PHYSX_FPS:
104        physx_scene = None
105        for prim in stage.Traverse():
106            if prim.IsA(UsdPhysics.Scene):
107                physx_scene = PhysxSchema.PhysxSceneAPI.Apply(prim)
108                break
109        if physx_scene is None:
110            UsdPhysics.Scene.Define(stage, "/PhysicsScene")
111            physx_scene = PhysxSchema.PhysxSceneAPI.Apply(stage.GetPrimAtPath("/PhysicsScene"))
112
113        # Time step for the physics simulation
114        # Default: 60.0
115        physx_scene.GetTimeStepsPerSecondAttr().Set(PHYSX_FPS)
116
117        # Minimum simulation frequency to prevent clamping; if the frame rate drops below this,
118        # physics steps are discarded to avoid app slowdown if the overall frame rate is too low.
119        # Default: 30.0
120        # NOTE: Matching `minFrameRate` with `TimeStepsPerSecond` ensures a single physics step per update.
121        carb.settings.get_settings().set("/persistent/simulation/minFrameRate", MIN_SIM_FPS)
122
123    # Throttle Render/UI/Main thread update rate
124    if LIMIT_APP_FPS:
125        # Enable rate limiting of the main run loop (UI, rendering, etc.)
126        # Default: False
127        carb.settings.get_settings().set("/app/runLoops/main/rateLimitEnabled", LIMIT_APP_FPS)
128
129        # FPS limit of the main run loop (UI, rendering, etc.)
130        # Default: 120
131        # NOTE: disabled if `/app/player/useFixedTimeStepping` is False
132        carb.settings.get_settings().set("/app/runLoops/main/rateLimitFrequency", int(APP_FPS))
133
134    # Simulations can be selectively disabled (or toggled at specific times)
135    if DISABLE_SIMULATIONS:
136        carb.settings.get_settings().set("/app/player/playSimulations", False)
137
138    print("Configuration:")
139    print(f"  Timeline:")
140    print(f"    - Stage FPS: {STAGE_FPS}  (/app/stage/timeCodesPerSecond)")
141    print(f"    - Fixed time stepping: {USE_FIXED_TIME_STEPPING}  (/app/player/useFixedTimeStepping)")
142    print(f"    - Play every frame: {PLAY_EVERY_FRAME}  (/app/player/useFastMode)")
143    print(f"    - Subsample rate: {SUBSAMPLE_RATE}  (/app/player/timelineSubsampleRate)")
144    print(f"    - Play delay compensation: {PLAY_DELAY_COMPENSATION}s  (/app/player/CompensatePlayDelayInSecs)")
145    print(f"  Physics:")
146    print(f"    - PhysX FPS: {PHYSX_FPS}  (physxScene.timeStepsPerSecond)")
147    print(f"    - Min simulation FPS: {MIN_SIM_FPS}  (/persistent/simulation/minFrameRate)")
148    print(f"    - Simulations enabled: {not DISABLE_SIMULATIONS}  (/app/player/playSimulations)")
149    print(f"  Rendering:")
150    print(
151        f"    - App FPS limit: {APP_FPS if LIMIT_APP_FPS else 'unlimited'}  (/app/runLoops/main/rateLimitFrequency)"
152    )
153
154    # Start the timeline
155    print(f"Starting the timeline...")
156    timeline.set_current_time(0)
157    timeline.set_end_time(10000)
158    timeline.set_looping(False)
159    timeline.play()
160    timeline.commit()
161    wall_start_time = time.time()
162
163    # Subscribe to events
164    print(f"Subscribing to events...")
165    timeline_events = []
166    timeline_sub = timeline.get_timeline_event_stream().create_subscription_to_pop(on_timeline_event)
167    physx_events = []
168    physx_sub = omni.physx.get_physx_interface().subscribe_physics_step_events(on_physics_step)
169    stage_render_events = []
170    stage_render_sub = carb.eventdispatcher.get_eventdispatcher().observe_event(
171        event_name=omni.usd.get_context().stage_rendering_event_name(
172            omni.usd.StageRenderingEventType.NEW_FRAME, True
173        ),
174        on_event=on_stage_render_event,
175        observer_name="subscribers_and_events.on_stage_render_event",
176    )
177    app_update_events = []
178    app_sub = carb.eventdispatcher.get_eventdispatcher().observe_event(
179        event_name=omni.kit.app.GLOBAL_EVENT_UPDATE,
180        on_event=on_app_update,
181        observer_name="subscribers_and_events.on_app_update",
182    )
183
184    # Run app updates and cache events
185    print(f"Starting running the application for {NUM_APP_UPDATES} updates...")
186    for i in range(NUM_APP_UPDATES):
187        if VERBOSE:
188            print(f"[app update loop][{i+1}/{NUM_APP_UPDATES}]")
189        await omni.kit.app.get_app().next_update_async()
190    elapsed_wall_time = time.time() - wall_start_time
191    print(f"Finished running the application for {NUM_APP_UPDATES} updates...")
192
193    # Stop timeline and unsubscribe from all events
194    print(f"Stopping timeline and unsubscribing from all events...")
195    timeline.stop()
196    if app_sub:
197        app_sub.reset()
198        app_sub = None
199    if stage_render_sub:
200        stage_render_sub.reset()
201        stage_render_sub = None
202    if physx_sub:
203        physx_sub.unsubscribe()
204        physx_sub = None
205    if timeline_sub:
206        timeline_sub.unsubscribe()
207        timeline_sub = None
208
209    # Print summary statistics
210    print("\nStats:")
211    print(f"- App updates: {NUM_APP_UPDATES}")
212    print(f"- Wall time: {elapsed_wall_time:.4f} seconds")
213    print(f"- Timeline events: {len(timeline_events)}")
214    print(f"- Physics events: {len(physx_events)}")
215    print(f"- Stage render events: {len(stage_render_events)}")
216    print(f"- App update events: {len(app_update_events)}")
217
218    # Calculate and display real-time performance factor
219    if len(physx_events) > 0:
220        sim_time = sum(physx_events)
221        realtime_factor = sim_time / elapsed_wall_time if elapsed_wall_time > 0 else 0
222        print(f"- Simulation time: {sim_time:.4f}s")
223        print(f"- Real-time factor: {realtime_factor:.2f}x")
224
225asyncio.ensure_future(run_subscribers_and_events_async())
Subscribers and Events at Custom FPS
  1from isaacsim import SimulationApp
  2
  3simulation_app = SimulationApp({"headless": False})
  4
  5import time
  6
  7import carb.eventdispatcher
  8import carb.settings
  9import omni.kit.app
 10import omni.physx
 11import omni.timeline
 12import omni.usd
 13from pxr import PhysxSchema, UsdPhysics
 14
 15# TIMELINE / STAGE
 16USE_CUSTOM_TIMELINE_SETTINGS = True
 17USE_FIXED_TIME_STEPPING = True
 18PLAY_EVERY_FRAME = True
 19PLAY_DELAY_COMPENSATION = 0.0
 20SUBSAMPLE_RATE = 1
 21STAGE_FPS = 30.0
 22
 23# PHYSX
 24USE_CUSTOM_PHYSX_FPS = False
 25PHYSX_FPS = 60.0
 26MIN_SIM_FPS = 30
 27
 28# Simulations can also be enabled/disabled at runtime
 29DISABLE_SIMULATIONS = False
 30
 31# APP / RENDER
 32LIMIT_APP_FPS = False
 33APP_FPS = 120
 34
 35# Number of app updates to run while collecting events
 36NUM_APP_UPDATES = 100
 37
 38# Print the captured events
 39VERBOSE = False
 40
 41
 42def on_timeline_event(event: omni.timeline.TimelineEventType):
 43    global timeline_events
 44    if event.type == omni.timeline.TimelineEventType.CURRENT_TIME_TICKED.value:
 45        timeline_events.append(event.payload)
 46        if VERBOSE:
 47            print(f"  [timeline][{len(timeline_events)}] {event.payload}")
 48
 49
 50def on_physics_step(dt: float):
 51    global physx_events
 52    physx_events.append(dt)
 53    if VERBOSE:
 54        print(f"  [physics][{len(physx_events)}] dt={dt}")
 55
 56
 57def on_stage_render_event(event: carb.eventdispatcher.Event):
 58    global stage_render_events
 59    stage_render_events.append(event.event_name)
 60    if VERBOSE:
 61        print(f"  [stage render][{len(stage_render_events)}] {event.event_name}")
 62
 63
 64def on_app_update(event: carb.eventdispatcher.Event):
 65    global app_update_events
 66    app_update_events.append(event.event_name)
 67    if VERBOSE:
 68        print(f"  [app update][{len(app_update_events)}] {event.event_name}")
 69
 70
 71stage = omni.usd.get_context().get_stage()
 72timeline = omni.timeline.get_timeline_interface()
 73
 74
 75if USE_CUSTOM_TIMELINE_SETTINGS:
 76    # Ideal to make simulation and animation synchronized.
 77    # Default: True in editor, False in standalone.
 78    # NOTE:
 79    # - It may limit the frame rate (see 'timeline.set_play_every_frame') such that the elapsed wall clock time matches the frame's delta time.
 80    # - If the app runs slower than this, animation playback may slow down (see 'CompensatePlayDelayInSecs').
 81    # - For performance benchmarks, turn this off or set a very high target in `timeline.set_target_framerate`
 82    carb.settings.get_settings().set("/app/player/useFixedTimeStepping", USE_FIXED_TIME_STEPPING)
 83
 84    # This compensates for frames that require more computation time than the frame's fixed delta time, by temporarily speeding up playback.
 85    # The parameter represents the length of these "faster" playback periods, which means that it must be larger than the fixed frame time to take effect.
 86    # Default: 0.0
 87    # NOTE:
 88    # - only effective if `useFixedTimeStepping` is set to True
 89    # - setting a large value results in long fast playback after a huge lag spike
 90    carb.settings.get_settings().set("/app/player/CompensatePlayDelayInSecs", PLAY_DELAY_COMPENSATION)
 91
 92    # If set to True, no frames are skipped and in every frame time advances by `1 / TimeCodesPerSecond`.
 93    # Default: False
 94    # NOTE:
 95    # - only effective if `useFixedTimeStepping` is set to True
 96    # - simulation is usually faster than real-time and processing is only limited by the frame rate of the runloop
 97    # - useful for recording
 98    # - same as `carb.settings.get_settings().set("/app/player/useFastMode", PLAY_EVERY_FRAME)`
 99    timeline.set_play_every_frame(PLAY_EVERY_FRAME)
100
101    # Timeline sub-stepping, i.e. how many times updates are called (update events are dispatched) each frame.
102    # Default: 1
103    # NOTE: same as `carb.settings.get_settings().set("/app/player/timelineSubsampleRate", SUBSAMPLE_RATE)`
104    timeline.set_ticks_per_frame(SUBSAMPLE_RATE)
105
106    # Time codes per second for the stage
107    # NOTE: same as `stage.SetTimeCodesPerSecond(STAGE_FPS)` and `carb.settings.get_settings().set("/app/stage/timeCodesPerSecond", STAGE_FPS)`
108    timeline.set_time_codes_per_second(STAGE_FPS)
109
110
111# Create a PhysX scene to set the physics time step
112if USE_CUSTOM_PHYSX_FPS:
113    physx_scene = None
114    for prim in stage.Traverse():
115        if prim.IsA(UsdPhysics.Scene):
116            physx_scene = PhysxSchema.PhysxSceneAPI.Apply(prim)
117            break
118    if physx_scene is None:
119        UsdPhysics.Scene.Define(stage, "/PhysicsScene")
120        physx_scene = PhysxSchema.PhysxSceneAPI.Apply(stage.GetPrimAtPath("/PhysicsScene"))
121
122    # Time step for the physics simulation
123    # Default: 60.0
124    physx_scene.GetTimeStepsPerSecondAttr().Set(PHYSX_FPS)
125
126    # Minimum simulation frequency to prevent clamping; if the frame rate drops below this,
127    # physics steps are discarded to avoid app slowdown if the overall frame rate is too low.
128    # Default: 30.0
129    # NOTE: Matching `minFrameRate` with `TimeStepsPerSecond` ensures a single physics step per update.
130    carb.settings.get_settings().set("/persistent/simulation/minFrameRate", MIN_SIM_FPS)
131
132
133# Throttle Render/UI/Main thread update rate
134if LIMIT_APP_FPS:
135    # Enable rate limiting of the main run loop (UI, rendering, etc.)
136    # Default: False
137    carb.settings.get_settings().set("/app/runLoops/main/rateLimitEnabled", LIMIT_APP_FPS)
138
139    # FPS limit of the main run loop (UI, rendering, etc.)
140    # Default: 120
141    # NOTE: disabled if `/app/player/useFixedTimeStepping` is False
142    carb.settings.get_settings().set("/app/runLoops/main/rateLimitFrequency", int(APP_FPS))
143
144
145# Simulations can be selectively disabled (or toggled at specific times)
146if DISABLE_SIMULATIONS:
147    carb.settings.get_settings().set("/app/player/playSimulations", False)
148
149print("Configuration:")
150print(f"  Timeline:")
151print(f"    - Stage FPS: {STAGE_FPS}  (/app/stage/timeCodesPerSecond)")
152print(f"    - Fixed time stepping: {USE_FIXED_TIME_STEPPING}  (/app/player/useFixedTimeStepping)")
153print(f"    - Play every frame: {PLAY_EVERY_FRAME}  (/app/player/useFastMode)")
154print(f"    - Subsample rate: {SUBSAMPLE_RATE}  (/app/player/timelineSubsampleRate)")
155print(f"    - Play delay compensation: {PLAY_DELAY_COMPENSATION}s  (/app/player/CompensatePlayDelayInSecs)")
156print(f"  Physics:")
157print(f"    - PhysX FPS: {PHYSX_FPS}  (physxScene.timeStepsPerSecond)")
158print(f"    - Min simulation FPS: {MIN_SIM_FPS}  (/persistent/simulation/minFrameRate)")
159print(f"    - Simulations enabled: {not DISABLE_SIMULATIONS}  (/app/player/playSimulations)")
160print(f"  Rendering:")
161print(f"    - App FPS limit: {APP_FPS if LIMIT_APP_FPS else 'unlimited'}  (/app/runLoops/main/rateLimitFrequency)")
162
163
164# Start the timeline
165print(f"Starting the timeline...")
166timeline.set_current_time(0)
167timeline.set_end_time(10000)
168timeline.set_looping(False)
169timeline.play()
170timeline.commit()
171wall_start_time = time.time()
172
173# Subscribe to events
174print(f"Subscribing to events...")
175timeline_events = []
176timeline_sub = timeline.get_timeline_event_stream().create_subscription_to_pop(on_timeline_event)
177physx_events = []
178physx_sub = omni.physx.get_physx_interface().subscribe_physics_step_events(on_physics_step)
179stage_render_events = []
180stage_render_sub = carb.eventdispatcher.get_eventdispatcher().observe_event(
181    event_name=omni.usd.get_context().stage_rendering_event_name(omni.usd.StageRenderingEventType.NEW_FRAME, True),
182    on_event=on_stage_render_event,
183    observer_name="subscribers_and_events.on_stage_render_event",
184)
185app_update_events = []
186app_sub = carb.eventdispatcher.get_eventdispatcher().observe_event(
187    event_name=omni.kit.app.GLOBAL_EVENT_UPDATE,
188    on_event=on_app_update,
189    observer_name="subscribers_and_events.on_app_update",
190)
191
192# Run app updates and cache events
193print(f"Starting running the application for {NUM_APP_UPDATES} updates.")
194for i in range(NUM_APP_UPDATES):
195    if VERBOSE:
196        print(f"[app update loop][{i+1}/{NUM_APP_UPDATES}]")
197    simulation_app.update()
198elapsed_wall_time = time.time() - wall_start_time
199print(f"Finished running the application for {NUM_APP_UPDATES} updates...")
200
201# Stop timeline and unsubscribe from all events
202timeline.stop()
203if app_sub:
204    app_sub.reset()
205    app_sub = None
206if stage_render_sub:
207    stage_render_sub.reset()
208    stage_render_sub = None
209if physx_sub:
210    physx_sub.unsubscribe()
211    physx_sub = None
212if timeline_sub:
213    timeline_sub.unsubscribe()
214    timeline_sub = None
215
216
217# Print summary statistics
218print("\nStats:")
219print(f"- App updates: {NUM_APP_UPDATES}")
220print(f"- Wall time: {elapsed_wall_time:.4f} seconds")
221print(f"- Timeline events: {len(timeline_events)}")
222print(f"- Physics events: {len(physx_events)}")
223print(f"- Stage render events: {len(stage_render_events)}")
224print(f"- App update events: {len(app_update_events)}")
225
226# Calculate and display real-time performance factor
227if len(physx_events) > 0:
228    sim_time = sum(physx_events)
229    realtime_factor = sim_time / elapsed_wall_time if elapsed_wall_time > 0 else 0
230    print(f"- Simulation time: {sim_time:.4f}s")
231    print(f"- Real-time factor: {realtime_factor:.2f}x")
232
233simulation_app.close()

Accessing Writer and Annotator Data at Custom FPS#

Example of how to trigger a writer and access annotator data at a custom FPS, with product rendering disabled when the data is not needed. The standalone example can also be run directly (on Windows use python.bat instead of python.sh):

./python.sh standalone_examples/api/isaacsim.replicator.examples/custom_fps_writer_annotator.py

Note

It is currently not possible to change timeline (stage) FPS after the replicator graph creation as it causes a graph reset. This issue is being addressed. As a workaround make sure you are setting the timeline (stage) parameters before creating the replicator graph.

Accessing Writer and Annotator Data at Custom FPS
  1import asyncio
  2import os
  3
  4import carb.settings
  5import omni.kit.app
  6import omni.replicator.core as rep
  7import omni.timeline
  8import omni.usd
  9
 10# Configuration
 11NUM_CAPTURES = 6
 12VERBOSE = True
 13
 14# NOTE: To avoid FPS delta misses make sure the sensor framerate is divisible by the timeline framerate
 15STAGE_FPS = 100.0
 16SENSOR_FPS = 10.0
 17SENSOR_DT = 1.0 / SENSOR_FPS
 18
 19
 20async def run_custom_fps_example_async(duration_seconds):
 21    # Create a new stage
 22    await omni.usd.get_context().new_stage_async()
 23
 24    # Set DLSS to Quality mode (2) for best SDG results , options: 0 (Performance), 1 (Balanced), 2 (Quality), 3 (Auto)
 25    carb.settings.get_settings().set("rtx/post/dlss/execMode", 2)
 26
 27    # Disable capture on play (data will only be accessed at custom times)
 28    carb.settings.get_settings().set("/omni/replicator/captureOnPlay", False)
 29
 30    # Make sure fixed time stepping is set (the timeline will be advanced with the same delta time)
 31    carb.settings.get_settings().set("/app/player/useFixedTimeStepping", True)
 32
 33    # Set the timeline parameters
 34    timeline = omni.timeline.get_timeline_interface()
 35    timeline.set_looping(False)
 36    timeline.set_current_time(0.0)
 37    timeline.set_end_time(10)
 38    timeline.set_time_codes_per_second(STAGE_FPS)
 39    timeline.play()
 40    timeline.commit()
 41
 42    # Create scene with a semantically annotated cube with physics
 43    rep.functional.create.dome_light(intensity=250)
 44    cube = rep.functional.create.cube(position=(0, 0, 3), semantics={"class": "cube"})
 45    rep.functional.physics.apply_collider(cube)
 46    rep.functional.physics.apply_rigid_body(cube)
 47
 48    # Create render product (disabled until data capture is needed)
 49    rp = rep.create.render_product("/OmniverseKit_Persp", (512, 512), name="rp")
 50    rp.hydra_texture.set_updates_enabled(False)
 51
 52    # Create a writer and an annotator as examples of different ways of accessing data
 53    out_dir_rgb = os.path.join(os.getcwd(), "_out_writer_fps_rgb")
 54    print(f"Writer data will be written to: {out_dir_rgb}")
 55    writer_rgb = rep.WriterRegistry.get("BasicWriter")
 56    writer_rgb.initialize(output_dir=out_dir_rgb, rgb=True)
 57    writer_rgb.attach(rp)
 58    annot_depth = rep.AnnotatorRegistry.get_annotator("distance_to_camera")
 59    annot_depth.attach(rp)
 60
 61    # Run the simulation for the given number of frames and access the data at the desired framerates
 62    print(
 63        f"Starting simulation: {duration_seconds:.2f}s duration, {SENSOR_FPS:.0f} FPS sensor, {STAGE_FPS:.0f} FPS timeline"
 64    )
 65
 66    frame_count = 0
 67    previous_time = timeline.get_current_time()
 68    elapsed_time = 0.0
 69    iteration = 0
 70
 71    while timeline.get_current_time() < duration_seconds:
 72        current_time = timeline.get_current_time()
 73        delta_time = current_time - previous_time
 74        elapsed_time += delta_time
 75
 76        # Simulation progress
 77        if VERBOSE:
 78            print(f"Step {iteration}: timeline time={current_time:.3f}s, elapsed time={elapsed_time:.3f}s")
 79
 80        # Trigger sensor at desired framerate (use small epsilon for floating point comparison)
 81        if elapsed_time >= SENSOR_DT - 1e-9:
 82            elapsed_time -= SENSOR_DT  # Reset with remainder to maintain accuracy
 83
 84            rp.hydra_texture.set_updates_enabled(True)
 85            await rep.orchestrator.step_async(delta_time=0.0, pause_timeline=False, rt_subframes=16)
 86            annot_data = annot_depth.get_data()
 87
 88            print(f"\n  >> Capturing frame {frame_count} at time={current_time:.3f}s | shape={annot_data.shape}\n")
 89            frame_count += 1
 90
 91            rp.hydra_texture.set_updates_enabled(False)
 92
 93        previous_time = current_time
 94        # Advance the app (timeline) by one frame
 95        await omni.kit.app.get_app().next_update_async()
 96        iteration += 1
 97
 98    # Wait for writer to finish
 99    await rep.orchestrator.wait_until_complete_async()
100
101
102# Run example with duration for all captures plus a buffer of 5 frames
103duration = (NUM_CAPTURES * SENSOR_DT) + (5.0 / STAGE_FPS)
104asyncio.ensure_future(run_custom_fps_example_async(duration_seconds=duration))
Accessing Writer and Annotator Data at Custom FPS
  1from isaacsim import SimulationApp
  2
  3from isaacsim import SimulationApp
  4
  5simulation_app = SimulationApp({"headless": False})
  6
  7import os
  8
  9import carb.settings
 10import omni.kit.app
 11import omni.replicator.core as rep
 12import omni.timeline
 13import omni.usd
 14
 15# Configuration
 16NUM_CAPTURES = 6
 17VERBOSE = True
 18
 19# NOTE: To avoid FPS delta misses make sure the sensor framerate is divisible by the timeline framerate
 20STAGE_FPS = 100.0
 21SENSOR_FPS = 10.0
 22SENSOR_DT = 1.0 / SENSOR_FPS
 23
 24
 25def run_custom_fps_example(duration_seconds):
 26    # Create a new stage
 27    omni.usd.get_context().new_stage()
 28
 29    # Set DLSS to Quality mode (2) for best SDG results , options: 0 (Performance), 1 (Balanced), 2 (Quality), 3 (Auto)
 30    carb.settings.get_settings().set("rtx/post/dlss/execMode", 2)
 31
 32    # Disable capture on play (data will only be accessed at custom times)
 33    carb.settings.get_settings().set("/omni/replicator/captureOnPlay", False)
 34
 35    # Make sure fixed time stepping is set (the timeline will be advanced with the same delta time)
 36    carb.settings.get_settings().set("/app/player/useFixedTimeStepping", True)
 37
 38    # Set the timeline parameters
 39    timeline = omni.timeline.get_timeline_interface()
 40    timeline.set_looping(False)
 41    timeline.set_current_time(0.0)
 42    timeline.set_end_time(10)
 43    timeline.set_time_codes_per_second(STAGE_FPS)
 44    timeline.play()
 45    timeline.commit()
 46
 47    # Create scene with a semantically annotated cube with physics
 48    rep.functional.create.dome_light(intensity=250)
 49    cube = rep.functional.create.cube(position=(0, 0, 3), semantics={"class": "cube"})
 50    rep.functional.physics.apply_collider(cube)
 51    rep.functional.physics.apply_rigid_body(cube)
 52
 53    # Create render product (disabled until data capture is needed)
 54    rp = rep.create.render_product("/OmniverseKit_Persp", (512, 512), name="rp")
 55    rp.hydra_texture.set_updates_enabled(False)
 56
 57    # Create a writer and an annotator as examples of different ways of accessing data
 58    out_dir_rgb = os.path.join(os.getcwd(), "_out_writer_fps_rgb")
 59    print(f"Writer data will be written to: {out_dir_rgb}")
 60    writer_rgb = rep.WriterRegistry.get("BasicWriter")
 61    writer_rgb.initialize(output_dir=out_dir_rgb, rgb=True)
 62    writer_rgb.attach(rp)
 63    annot_depth = rep.AnnotatorRegistry.get_annotator("distance_to_camera")
 64    annot_depth.attach(rp)
 65
 66    # Run the simulation for the given number of frames and access the data at the desired framerates
 67    print(
 68        f"Starting simulation: {duration_seconds:.2f}s duration, {SENSOR_FPS:.0f} FPS sensor, {STAGE_FPS:.0f} FPS timeline"
 69    )
 70
 71    frame_count = 0
 72    previous_time = timeline.get_current_time()
 73    elapsed_time = 0.0
 74    iteration = 0
 75
 76    while timeline.get_current_time() < duration_seconds:
 77        current_time = timeline.get_current_time()
 78        delta_time = current_time - previous_time
 79        elapsed_time += delta_time
 80
 81        # Simulation progress
 82        if VERBOSE:
 83            print(f"Step {iteration}: timeline time={current_time:.3f}s, elapsed time={elapsed_time:.3f}s")
 84
 85        # Trigger sensor at desired framerate (use small epsilon for floating point comparison)
 86        if elapsed_time >= SENSOR_DT - 1e-9:
 87            elapsed_time -= SENSOR_DT  # Reset with remainder to maintain accuracy
 88
 89            rp.hydra_texture.set_updates_enabled(True)
 90            rep.orchestrator.step(delta_time=0.0, pause_timeline=False, rt_subframes=16)
 91            annot_data = annot_depth.get_data()
 92
 93            print(f"\n  >> Capturing frame {frame_count} at time={current_time:.3f}s | shape={annot_data.shape}\n")
 94            frame_count += 1
 95
 96            rp.hydra_texture.set_updates_enabled(False)
 97
 98        previous_time = current_time
 99        # Advance the app (timeline) by one frame
100        simulation_app.update()
101        iteration += 1
102
103    # Wait for writer to finish
104    rep.orchestrator.wait_until_complete()
105
106
107# Run example with duration for all captures plus a buffer of 5 frames
108duration = (NUM_CAPTURES * SENSOR_DT) + (5.0 / STAGE_FPS)
109run_custom_fps_example(duration_seconds=duration)
110
111simulation_app.close()

Cosmos Writer Example#

This example demonstrates the CosmosWriter for capturing multi-modal synthetic data compatible with NVIDIA Cosmos world foundation models. It creates a simple falling box scene and captures synchronized RGB, segmentation, depth, and edge data (images and videos) that can be used with Cosmos Transfer to generate photorealistic variations.

For a more detailed tutorial please see Cosmos Synthetic Data Generation.

The standalone example can also be run directly (on Windows use python.bat instead of python.sh):

./python.sh standalone_examples/api/isaacsim.replicator.examples/cosmos_writer_simple.py
Cosmos Writer Example
 1import asyncio
 2import os
 3
 4import carb.settings
 5import omni.replicator.core as rep
 6import omni.timeline
 7import omni.usd
 8
 9SEGMENTATION_MAPPING = {
10    "plane": [0, 0, 255, 255],
11    "cube": [255, 0, 0, 255],
12    "sphere": [0, 255, 0, 255],
13}
14NUM_FRAMES = 60
15
16async def run_cosmos_example_async(num_frames, segmentation_mapping=None):
17    # Create a new stage
18    omni.usd.get_context().new_stage()
19
20    # CosmosWriter requires script nodes to be enabled
21    carb.settings.get_settings().set_bool("/app/omni.graph.scriptnode/opt_in", True)
22
23    # Disable capture on play, data is captured manually using the step function
24    rep.orchestrator.set_capture_on_play(False)
25
26    # Set DLSS to Quality mode (2) for best SDG results (Options: 0 (Performance), 1 (Balanced), 2 (Quality), 3 (Auto)
27    carb.settings.get_settings().set("rtx/post/dlss/execMode", 2)
28
29    # Set the stage properties
30    rep.settings.set_stage_up_axis("Z")
31    rep.settings.set_stage_meters_per_unit(1.0)
32    rep.functional.create.dome_light(intensity=500)
33
34    # Create the scenario with a ground plane and a falling sphere and cube.
35    plane = rep.functional.create.plane(position=(0, 0, 0), scale=(10, 10, 1), semantics={"class": "plane"})
36    rep.functional.physics.apply_collider(plane)
37
38    sphere = rep.functional.create.sphere(position=(0, 0, 3), semantics={"class": "sphere"})
39    rep.functional.physics.apply_collider(sphere)
40    rep.functional.physics.apply_rigid_body(sphere)
41
42    cube = rep.functional.create.cube(position=(1, 1, 2), scale=0.5, semantics={"class": "cube"})
43    rep.functional.physics.apply_collider(cube)
44    rep.functional.physics.apply_rigid_body(cube)
45
46    # Set up the writer
47    camera = rep.functional.create.camera(position=(5, 5, 3), look_at=(0, 0, 0))
48    rp = rep.create.render_product(camera, (1280, 720))
49    out_dir = os.path.join(os.getcwd(), "_out_cosmos_simple")
50    print(f"Output directory: {out_dir}")
51    cosmos_writer = rep.WriterRegistry.get("CosmosWriter")
52    cosmos_writer.initialize(output_dir=out_dir, segmentation_mapping=segmentation_mapping)
53    cosmos_writer.attach(rp)
54
55    # Start the simulation
56    timeline = omni.timeline.get_timeline_interface()
57    timeline.play()
58
59    # Capture a frame every app update
60    for i in range(num_frames):
61        print(f"Frame {i+1}/{num_frames}")
62        await omni.kit.app.get_app().next_update_async()
63        await rep.orchestrator.step_async(delta_time=0.0, pause_timeline=False)
64    timeline.pause()
65
66    # Wait for all data to be written
67    await rep.orchestrator.wait_until_complete_async()
68    print("Data generation complete!")
69    cosmos_writer.detach()
70    rp.destroy()
71
72asyncio.ensure_future(run_cosmos_example_async(num_frames=NUM_FRAMES, segmentation_mapping=SEGMENTATION_MAPPING))
Cosmos Writer Example
 1from isaacsim import SimulationApp
 2
 3simulation_app = SimulationApp(launch_config={"headless": False})
 4
 5import os
 6
 7import carb.settings
 8import omni.replicator.core as rep
 9import omni.timeline
10import omni.usd
11
12SEGMENTATION_MAPPING = {
13    "plane": [0, 0, 255, 255],
14    "cube": [255, 0, 0, 255],
15    "sphere": [0, 255, 0, 255],
16}
17NUM_FRAMES = 60
18
19
20def run_cosmos_example(num_frames, segmentation_mapping=None):
21    # Create a new stage
22    omni.usd.get_context().new_stage()
23
24    # CosmosWriter requires script nodes to be enabled
25    carb.settings.get_settings().set_bool("/app/omni.graph.scriptnode/opt_in", True)
26
27    # Disable capture on play, data is captured manually using the step function
28    rep.orchestrator.set_capture_on_play(False)
29
30    # Set DLSS to Quality mode (2) for best SDG results (Options: 0 (Performance), 1 (Balanced), 2 (Quality), 3 (Auto)
31    carb.settings.get_settings().set("rtx/post/dlss/execMode", 2)
32
33    # Set the stage properties
34    rep.settings.set_stage_up_axis("Z")
35    rep.settings.set_stage_meters_per_unit(1.0)
36    rep.functional.create.dome_light(intensity=500)
37
38    # Create the scenario with a ground plane and a falling sphere and cube.
39    plane = rep.functional.create.plane(position=(0, 0, 0), scale=(10, 10, 1), semantics={"class": "plane"})
40    rep.functional.physics.apply_collider(plane)
41
42    sphere = rep.functional.create.sphere(position=(0, 0, 3), semantics={"class": "sphere"})
43    rep.functional.physics.apply_collider(sphere)
44    rep.functional.physics.apply_rigid_body(sphere)
45
46    cube = rep.functional.create.cube(position=(1, 1, 2), scale=0.5, semantics={"class": "cube"})
47    rep.functional.physics.apply_collider(cube)
48    rep.functional.physics.apply_rigid_body(cube)
49
50    # Set up the writer
51    camera = rep.functional.create.camera(position=(5, 5, 3), look_at=(0, 0, 0))
52    rp = rep.create.render_product(camera, (1280, 720))
53    out_dir = os.path.join(os.getcwd(), "_out_cosmos_simple")
54    print(f"Output directory: {out_dir}")
55    cosmos_writer = rep.WriterRegistry.get("CosmosWriter")
56    cosmos_writer.initialize(output_dir=out_dir, segmentation_mapping=segmentation_mapping)
57    cosmos_writer.attach(rp)
58
59    # Start the simulation
60    timeline = omni.timeline.get_timeline_interface()
61    timeline.play()
62
63    # Capture a frame every app update
64    for i in range(num_frames):
65        print(f"Frame {i+1}/{num_frames}")
66        simulation_app.update()
67        rep.orchestrator.step(delta_time=0.0, pause_timeline=False)
68    timeline.pause()
69
70    # Wait for all data to be written
71    rep.orchestrator.wait_until_complete()
72    print("Data generation complete!")
73    cosmos_writer.detach()
74    rp.destroy()
75
76
77run_cosmos_example(num_frames=NUM_FRAMES, segmentation_mapping=SEGMENTATION_MAPPING)
78
79simulation_app.close()