I have a scenario where i need to do hundreds of renders, each render with a different series of usd layers. To individually load and render out each scene takes about a week of work, and i am writing an extension to automate the render process, but am having difficulties.
The first step is to recursively loop through my variables and save the persistent usd’s, ready to be sent to Farm. I have a more complex version of the program i am pasting here, but i have recreated a minimal version of the recursion to simulate the bug or problem i am having.
On the first loop, everything works as expected, the initial persistent usd loads, i am able to programatically add layers to it, programatically save it, then call the second recursive loop. This is where it stumbles, it is able to load the persistent level again, but when calling the event function, if you do some logging, you see that it loads 5 events on opening the USD and then crashes to the desktop just before it gets to the ASSETS_LOADED event. And so my automated tool crashes here and i cannot get the recursion to continue and save all the USD’s i need.
The code for the minimal replication is here:
import threading import omni.ext import omni.ui as ui import omni.usd import omni.kit import asyncio import json import sys import getpass import carb import time import omni.services.client as _services_client # Any class derived from `omni.ext.IExt` in top level module (defined in `python.modules` of `extension.toml`) will be # instantiated when extension gets enabled and `on_startup(ext_id)` will be called. Later when extension gets disabled # on_shutdown() is called. class MyExtension(omni.ext.IExt): persistentLevel = "E:/Programming/IKHNucleus/Omni IMKH/2400mm/IMK_Foliage.usd" layer1 = "E:/Programming/IKHNucleus/Omni IMKH/2400mm/IMK_Rocks.usd" layer2 = "E:/Programming/IKHNucleus/Omni IMKH/2400mm/IMK_Ecohome_24_Slab.usd" layer3Loop1 = "E:/Programming/IKHNucleus/Omni IMKH/2400mm/IMK_Z_HardieFlex24.usd" layer3Loop2 = "E:/Programming/IKHNucleus/Omni IMKH/2400mm/IMK_Z_Primeline24.usd" saveLocationLoop1 = "E:/Programming/IKHNucleus/Omni IMKH/Save/O1_0-O2_0-O3_0.usd" saveLocationLoop2 = "E:/Programming/IKHNucleus/Omni IMKH/Save/O1_0-O2_0-O3_1.usd" simulateLoop = 0 assetsLoaded = 0 inst = '' def on_stage_event(event): # On both loops, this event is called multiple times until finally the assets are loaded for the root layer # On the second recursive loop, all the events are called execpt for ASSETS_LOADED, this is where it crashes to desktop if event.type == int(omni.usd.StageEventType.ASSETS_LOADED): stage = omni.usd.get_context().get_stage() root_layer = stage.GetRootLayer() if MyExtension.assetsLoaded == 0: root_layer.subLayerPaths.append(MyExtension.layer1) MyExtension.assetsLoaded = 1 elif MyExtension.assetsLoaded == 1: root_layer.subLayerPaths.append(MyExtension.layer2) MyExtension.assetsLoaded = 2 elif MyExtension.assetsLoaded == 2: if MyExtension.simulateLoop == 0: root_layer.subLayerPaths.append(MyExtension.layer3Loop1) elif MyExtension.simulateLoop == 1: root_layer.subLayerPaths.append(MyExtension.layer3Loop2) MyExtension.assetsLoaded = 3 elif MyExtension.assetsLoaded == 3: if MyExtension.simulateLoop == 0: omni.usd.get_context().save_as_stage(MyExtension.saveLocationLoop1) elif MyExtension.simulateLoop == 1: omni.usd.get_context().save_as_stage(MyExtension.saveLocationLoop2) if event.type == int(omni.usd.StageEventType.SAVED): MyExtension.simulateLoop += 1 MyExtension.assetsLoaded = 0 if MyExtension.simulateLoop <= 1: #Call render loop recursively MyExtension.renderLoop() def renderLoop(): # Begin recursive function event_stream = omni.usd.get_context().get_stage_event_stream() MyExtension.stage_event_sub = event_stream.create_subscription_to_pop(MyExtension.on_stage_event) if MyExtension.simulateLoop == 0: omni.usd.get_context().open_stage(MyExtension.persistentLevel) elif MyExtension.simulateLoop == 1: omni.usd.get_context().open_stage(MyExtension.persistentLevel) # ext_id is current extension id. It can be used with extension manager to query additional information, like where # this extension is located on filesystem. def on_startup(self, ext_id): print("[omni.hello.world] MyExtension startup") self._window_title = "ConceptV Render Automation" self._menu_path = "Window/ConceptV Render" self._window = None try: self._menu = omni.kit.ui.get_editor_menu().add_item( self._menu_path, self.show_window, toggle=True, value=False ) except Exception as e: self._menu = None def on_shutdown(self): print("[omni.hello.world] MyExtension shutdown") if self._window: self._window.set_visibility_changed_fn(None) self._window = None self._menu = None def build_window(self): self._window = ui.Window(self._window_title, width=300, height=300, visible=True) self._window.set_visibility_changed_fn(self._visibility_changed_fn) with self._window.frame: with ui.VStack(): ui.Label("Load layers and begin render") def load_layers(): MyExtension.renderLoop() ui.Button("Load Layers", clicked_fn=lambda: load_layers()) def show_window(self, menu, value): if not self._window: self.build_window() elif self._window: self._window.visible = value def _visibility_changed_fn(self, value): if self._menu: omni.kit.ui.get_editor_menu().set_value(self._menu_path, value)