Hello @simon.steinmann , @Humai9! Thank you for your interest in Replicator. One of the core concepts of Replicator is providing customizability so that you have the freedom to produce your own custom components. We know we still have work to do to simplify this process. Once we have more improvements on this front, we will provide detailed steps and examples to write custom randomizers, so keep an eye out for that. That said, such custom functions are absolutely possible now, and an example of the desired functionality is provided below.
One of the first things to understand is that the python script is executing only once and only creates a graph detailing the steps to take at each frame. To add custom functionality to the graph, it’s necessary to create a custom node, which is accomplished by using AutoFunc to wrap a python function. Please let us know if you have more questions or any feedback. Your questions help improve Replicator and are incredibly valuable. Thank you!
import omni.replicator.core as rep
import omni.graph.core as og
import numpy as np
frame = 0
# The AutoFunc decorator will create a new OmniGraph node with the specified inputs/output
# See https://docs.omniverse.nvidia.com/py/kit/source/extensions/omni.graph/docs/autonode.html
@og.AutoFunc(module_name="omni.replicator")
def ComputeCameraPos(distance: float, elevation: float, numSamples: int = 1) -> og.Bundle:
# Note 1: numSamples input currently required
# Note 2: Only bundle output currently supported, this will be expanded in the future.
# Use global to have access to a persistent `frame` variable
global frame
print("FRAME", frame)
azimuth = frame * np.radians(3.6)
frame += 1
x = np.cos(azimuth) * np.cos(elevation) * distance
y = np.sin(azimuth) * np.cos(elevation) * distance
z = np.sin(elevation) * distance
bundle = og.Bundle("return", False)
bundle.create_attribute("values", og.Type(og.BaseDataType.DOUBLE, 3, 1)).value = [[x, y, z]]
return bundle
# This will allow the AutoFunc return attribute `out_0` to be automatically connected to the pose node's `values` input
rep.utils.ATTRIBUTE_MAPPINGS.add(rep.utils.AttrMap("outputs_out_0", "inputs:values"))
# Register functionality into replicator
def compute_camera_pos(distance: float, elevation: float):
return rep.utils.create_node("omni.replicator.ComputeCameraPos", distance=distance, elevation=elevation)
rep.randomizer.register(compute_camera_pos)
# TEST
camera = rep.create.camera()
rp = rep.create.render_product(camera, (1024, 1024))
rep.create.cube()
with rep.trigger.on_frame(num_frames=100):
with camera:
rep.modify.pose(
position=rep.randomizer.compute_camera_pos(400, 45),
look_at=(0,0,0)
)