Hi @simon.steinmann , please check out the code snippet below. This works in the current release, but a different solution will be needed for the upcoming release due to changes in the way autofunc works. I’ll follow up with more info after the new release. For now, hopefully, this should unblock you, and be an example for this type of nesting.
import omni.replicator.core as rep
import omni.graph.core as og
import numpy as np
from typing import Any
import carb
rep.settings.set_render_rtx_realtime()
# PROTOTYPE SOLUTION
# Add functionality to ReplicatorItem
def set_input(self, attribute: str, value: Any):
if self.node is None:
raise ValueError(f"ReplicatorItem object has no associated node, unable to retrieve attribute {attribute}.")
if not self.node.get_attribute_exists(f"inputs:{attribute}"):
raise ValueError(f"ReplicatorItem node has no attribute matching: {attribute}.")
node_attribute = self.node.get_attribute(f"inputs:{attribute}")
resolved_type = node_attribute.get_resolved_type()
# Disconnect any existing connection
for conn in node_attribute.get_upstream_connections():
conn.disconnect(node_attribute, False)
# Set data type
node_attribute.set_resolved_type(resolved_type)
# Set attribute
return node_attribute.set(value)
rep.utils.ReplicatorItem.set_input = set_input
frame = 0
elevation_list = [12, 30, 60, 89.9]
distance_list = [1000, 1600]
color_list = [[0.2806969, 0.2806969, 0.2806969], [0.028681736, 0.104105994, 0.28571427]]
@og.AutoFunc(module_name="omni.replicator")
def ComputeCameraPos(distance: float, elevation: float, azimuth: 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
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, azimuth: float):
return rep.utils.create_node("omni.replicator.ComputeCameraPos", distance=distance, elevation=elevation, azimuth=azimuth)
rep.randomizer.register(compute_camera_pos)
camera = rep.create.camera()
rp = rep.create.render_product(camera, (1024, 1024))
writer = rep.WriterRegistry.get("BasicWriter")
writer.initialize(output_dir="_forloop", rgb=True)
writer.attach(rp)
rep.create.cube()
with rep.trigger.on_frame(num_frames=10000):
with rep.get.prims("/Replicator/Cube"):
color_sampler = rep.distribution.uniform((0., 0., 0.), (1., 1., 1.))
rep.randomizer.color(color_sampler)
with camera:
camera_pose = rep.randomizer.compute_camera_pos(0, 0, 0)
rep.modify.pose(
position=camera_pose,
look_at=(0, 0, 0)
)
async def main():
for color in color_list:
for elevation in elevation_list:
for distance in distance_list:
for azimuth in range(0, 10):
color_sampler.set_input("lower", color)
color_sampler.set_input("upper", color)
camera_pose.set_input("elevation", elevation)
camera_pose.set_input("distance", distance)
camera_pose.set_input("azimuth", azimuth * 3.6)
# Render one frame
await omni.kit.app.get_app().next_update_async()
# Start capture if not yet started
if not rep.orchestrator.get_is_started():
await rep.orchestrator._Orchestrator()._start_async()
rep.orchestrator.stop()
import asyncio
asyncio.ensure_future(main())