How to get current frame number in Replicator

Hi, I want to get the frame number, so I can create a sequence, not just randomized functions. I will post the example code below. You can run it in code script editor. The desired function would be the camera moving in a circle around the cube, looking at it. How can I achieve that functionality?

import omni.replicator.core as rep
import numpy as np
with rep.new_layer():
    camera = rep.create.camera(position=(0, 0, 1000))
    render_product = rep.create.render_product(camera, (1024, 1024))
    cube = rep.create.cube(semantics=[('class', 'cube')],  position=(0, 0 , 0) )

    azimuth=0
    elevation = np.radians(45)
    distance=500
    origin=(0, 0, 0)
    frame = 0

    with rep.trigger.on_frame(num_frames=100):
        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
        with camera:
            rep.modify.pose(position=(x, y, z), look_at=origin)
1 Like

Did you solve this problem? I am taking same problem now.
If you know how to solve this problem, let me know plz.

No I have not. In the actual graph scripting (Action Graph), the “on Frame” trigger has a frame number (int) output. But It does not seem to be accessible through scripting. If you come up with any solution or workaround, please post it here!

@simon.steinmann I’m still ramping up on replicator, but does this API help? omni.timeline — kit-sdk 103.1 documentation

Thanks for the link. I will have to investigate. Just for clarification can these different extensions with their API be combined in a script? From my understanding, the replicator script is not executed per se, but rather constructs an action graph, which then gets executed. I wonder how all these extension APIs act / function.

Fairly certain my suggestion is not going to help so I reached out to the dev team.

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)
		)
3 Likes

@jlafleche Thank you so much, this looks exactly like what I was looking for. This should address also my issues I had with a truly customised writer class. I will try it out soon and give any feedback I may have.

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