Using replicator to modify local positions of items

Hello,
I am using Replicator for randomizing the positions of items in a scene. I want to modify the positions such that the items move about their own local axis (i.e. they translate locally rather than globally). My current code looks like this:

import omni.replicator.core as rep import random seed = random.randint(545631, 1000000) rep.set_global_seed(seed) with rep.new_layer(): camera = rep.create.render_product( "/Camera", resolution=(1920, 1080) ) def item_randomizer(): items = rep.get.prims(path_pattern='items', prim_types=['Xform']) with items: rep.modify.pose( position_x = rep.distribution.uniform(-30, 30), ) rep.randomizer.register(item_randomizer) with rep.trigger.on_frame(num_frames=10): rep.randomizer.item_randomizer() basic_writer = rep.WriterRegistry.get("BasicWriter") basic_writer.initialize( output_dir="_Output", rgb=True, ) basic_writer.attach([camera]) rep.orchestrator.run() 

The command rep.modify.pose(position_x = rep.distribution.uniform(-30, 30),) moves all the items randomly to a global position between -30 and 30. What I want to do is that the items translate about their own current position by certain millimeters. I have searched far and wide but have not been able to find a solution for this. I would appreciate some insight on this topic.

Hello. Any update regarding the question?

I apologize for the delay in getting back to you and we appreciate your feedback! This is a known limitation that we are in the process of addressing. In the mean time, you can achieve relative positioning by creating your own custom node. Here’s an example based on your script above. Please reach out if you have any questions!

from typing import List import pxr import omni.replicator.core as rep import random import omni.graph.core as og import omni.graph.core.types as ot import omni.usd # Create a new type of node node_type_name = "omni.replicator.core.jitter" # Only create new node if it doesn't exist try: og.ObjectLookup.node_type(node_type_name) except og.OmniGraphError: @og.create_node_type(unique_name=node_type_name, add_execution_pins=True) def jitter(prims: ot.target, relative_positions: ot.float3array, jitters: ot.float3array): """Modify prim position relative to an existing position""" # Verify same number of prims to targets and jitters assert len(prims) == len(relative_positions) assert len(prims) == len(jitters) # Assume prim already has `xform:translate` op stage = omni.usd.get_context().get_stage() for prim_path, relative_position, jitter in zip(prims, relative_positions, jitters): prim = stage.GetPrimAtPath(str(prim_path)) if not prim.HasAttribute("xformOp:translate"): raise ValueError(f"Prim {prim.GetPath()} missing translate op") prim.GetAttribute("xformOp:translate").Set(tuple((relative_position + jitter).tolist())) # Integrate with replicator @rep.utils.ReplicatorWrapper def jitter(relative_positions: List[pxr.Gf.Vec3f], jitters: rep.utils.ReplicatorItem) -> og.Node: node = rep.utils.create_node(node_type_name, relative_positions=relative_positions) # Setup the dynamic attribute connection rep.utils._setup_random_attribute(node, input_name="jitters", attribute_value=jitters) return node rep.modify.register(jitter) # Test rep.settings.set_stage_meters_per_unit(1) rep.settings.set_stage_up_axis("Z") with rep.new_layer(): depth = 5 cubes = [] for i in range(depth): cubes.append(rep.create.cube(position=(i * 110, 0, 0))) def item_randomizer(): items = rep.get.prims(path_pattern='_Xform', prim_types=['Xform']) # Get existing baseline positions positions = [] for prim in items.get_output_prims()["prims"]: if not prim.HasAttribute("xformOp:translate"): raise ValueError(f"Prim {prim.GetPath()} missing translate op") positions.append(prim.GetAttribute("xformOp:translate").Get()) with items: print(positions) rep.modify.jitter( relative_positions=positions, jitters=rep.distribution.uniform((-30, 0, 0), (30, 0, 0)) ) rep.randomizer.register(item_randomizer) with rep.trigger.on_frame(num_frames=10): rep.randomizer.item_randomizer() rep.orchestrator.run() 

Note, another option which can be much simpler is to make use of USD’s hierarchy. By arranging prims in a tree, we can effectively achieve the same result using the built-in Replicator nodes.