Two on_frames triggers for two different randomizations

I have a scene (house, plants, time of day, objects scattered arround) and I have a camera. I want to randomize the scene every X frames and the camera position every Y frames where X > Y and the write function of my writer is also called every Y frames (such that a snapshot will be saves for each position of the camera).

I tried following this example:

But I am not able to get two different triggers (of two different freq).

import omni.replicator.core as rep

with rep.new_layer():

    camera = rep.create.camera(position=(0, 0, 10), look_at=(0, 0, 0))

    spheres = rep.create.sphere(semantics=[("class", "sphere")], position=(0, 0, 0), count=1)

    with rep.trigger.on_frame(num_frames=10,interval=5):
        with spheres:
            rep.modify.pose(
                position=rep.distribution.uniform((-2, 0, -3), (2, 0, 3))
            )
    with rep.trigger.on_frame(num_frames=50):
        with spheres:
            rep.randomizer.color(colors=rep.distribution.normal((0.1, 0.1, 0.1), (1.0, 1.0, 1.0)))

render_product = rep.create.render_product(camera, (512, 512))
writer = rep.WriterRegistry.get("BasicWriter")
writer.initialize(
    output_dir="C:\\Users\\dsiss\\Downloads\\output",
    rgb=True,
)
writer.attach([render_product])

The output shows that the position changes every five frames and the color changes every 10 frames?
you can see the output here: output - Google Drive

Thank you

Hi there,

there is a limitation on the graph execution scheduling when using multiple triggers on the same node (e.g.with spheres). If you would for example use a different node this would not be the case, see this example where with spheres is switched with another node, with cubes, and in this scenario the scheduling works as intended.

import omni.replicator.core as rep

with rep.new_layer():
    camera = rep.create.camera(position=(0, 0, 10), look_at=(0, 0, 0))
    spheres = rep.create.sphere(semantics=[("class", "sphere")], position=(0, 0, 0), count=1)
    cubes = rep.create.cube(semantics=[("class", "cube")], position=(0, 0, 0), count=1)

    with rep.trigger.on_frame(num_frames=10, interval=5):
        with spheres:
            rep.modify.pose(
                position=rep.distribution.uniform((-2, 0, -3), (2, 0, 3))
            )

    with rep.trigger.on_frame(num_frames=50):
        with cubes:
            rep.randomizer.color(colors=rep.distribution.normal((0.1, 0.1, 0.1), (1.0, 1.0, 1.0)))

render_product = rep.create.render_product(camera, (512, 512))
writer = rep.WriterRegistry.get("BasicWriter")
writer.initialize(output_dir="_out_on_frame", rgb=True)
writer.attach([render_product])

To avoid this you could use a custom trigger workflow calling replicator step in a loop:

Hi @ahaidu Thank you for your solution.
Ill add to it that the rt_subframes of both on_frame should be the same. otherwise the editor crashes.

I am still not able to find a solution for my test case. which is: randomizing the scattered objects on a plane every X frames and randomize the position of the camera on the plane once every Y frames where Y>X.

With the below solution, the camera position is scattered at the same rate as the scattering of the objects.

        with rep.trigger.on_frame(num_frames = 50, interval = 20, rt_subframes = 40): 
            scattered_objects = scatter_uniqe()
        with rep.trigger.on_frame(num_frames = 1000, rt_subframes = 40): 
            scatter_camera(scattered_objects)
        
        def scatter_uniqe():
            usd_paths = get_usd_files2()
            traversable_plane = rep.get.prim_at_path(plane_path)
        
            NUM_RANDOM_OBJECTS = len(usd_paths)
            MAX_ALLOWED_IN_SPACE = 50
            random_list = [random.randint(MAX_ALLOWED_IN_SPACE - 1, MAX_ALLOWED_IN_SPACE) for _ in range(MAX_ALLOWED_IN_SPACE)]
        
            instances = rep.randomizer.instantiate(paths = usd_paths, with_replacements = False, size = rep.distribution.choice(random_list), use_cache = False)
        
            with rep.utils.sequential():
                with instances:
                    rep.modify.pose(rotation =rep.distribution.uniform((0,0,0), (0,0,180)))
                    rep.randomizer.scatter_2d(traversable_plane, check_for_collisions=True)
        
            return instances



        def scatter_camera(scattered_objects):
        
            traversable_plane = rep.get.prim_at_path(plane_path)
            robot = rep.get.prim_at_path(base_link_holder_path)
        
            with rep.utils.sequential():
                with robot:
                    rep.randomizer.scatter_2d(traversable_plane, no_coll_prims= scattered_objects)

Hi there, I think the issue is again tha the two on_frame triggers share a common node, namelytraversable_plane. I would suggest for such scenarios where the randomizations start to get a bit more complex it make sense to use a more isaac sim approach, where you run the SDG in a loop, and in the loop you can advance simulation, trigger custom randomizations (replicator or non replicator) and capture the data. This makes it more straight forward to include state based events in the workflow:

Let me know if you need further guidance on getting started with this workflow.

Best,
Andrei

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.