Extension: omni.usd-1.12.2

Documentation Generated: Oct 22, 2024

Overview

Introduction

The Omni USD extension (omni.usd) is the Python frontend of omni.usd.core. It serves to load and initialize Pixar USD library, and Omniverse USD Resolver that supports opening USD from Omniverse/HTTP urls. It provides synchronous and asynchronous interfaces in C++ and Python to manage omni.usd.UsdContext, which will be introduced in section UsdContext. Besides those, this extension also provides common utilities and undoable commands for wrapped USD operations that can be shared for other extensions. It is the foundation component for all other extentions that need to access USD.

UsdContext

omni.usd.UsdContext is the container for a PXR_NS::UsdStage that manages the lifecycle of a UsdStage instance. Because of historical reasons, UsdContext also undertakes extra responsibilities, including managing Hydra Engines and rendering threads, selections, and etc. Developers can create multiple instances of UsdContext, while a default instance of UsdContext is instantiated after initialization of omni.usd extension, which can be accessed through API omni.usd.get_context(). Most of the components instantiated by Kit application use default UsdContext as the source of a UsdStage, like Viewport, Stage Window, and Layer Window. Therefore, all status changes from default UsdContext and all authoring to the stage inside it will be synced by those components, and rendered if they are enabled.

Programming Guide

The following section mainly introduces how to program with omni.usd in Python. For its C++ counterpart, you can refer to class omni::usd::UsdContext for reference.

UsdContext

As mentioned above, UsdContext is a thin container for a UsdStage. It doesn’t encapsulate all APIs of UsdStage, but exposes the UsdStage instance for developers to interact with, so that developers could still use native USD API to interact with a stage.

How to Access Default UsdContext and Manage Stage

Here are the common steps to get the default UsdContext and open/close a stage.

Python
  1. Import package:

   import omni.usd
  1. Get the default UsdContext:

   usd_context = omni.usd.get_context()
  1. Open a stage:

   result, error_str = await usd_context.open_stage_async(stage_url)

   # Gets UsdStage handle
   stage = usd_context.get_stage()
  1. Save a stage:

UsdContext provides APIs to save stage. Unlike the USD API Usd.Stage.Save(), omni.usd.UsdContext.save_stage_async(), omni.usd.UsdContext.save_as_stage_async() or omni.usd.UsdContext.save_layers_async() only saves layers in the local layer stack. It also provides more options for developers to choose which set of layers to save.

   # Saves the current stage (all layers in the local layer stack).
   result, error_str = await usd_context.save_stage_async()

   ...
   # Saves the current stage to a new location.
   result, error_str = await usd_context.save_as_stage_async(new_location_url)

   ...
   # Saves a specified set of layers only.
   result, error_str, saved_layers = await usd_context.save_layers_async("", list_of_layer_identifiers)

   ...
   # Saves a specified set of layers and also save-as root layer to a new location.
   # Unlike save_as_stage_async, it only saves those layers specified if they have pending edits. Those
   # layers that are not given but have pending edits will keep pending edits still.
   result, error_str, saved_layers = await usd_context.save_layers_async(new_root_location, list_of_layer_identifiers)
  1. Close a stage:

   error_str = await usd_context.close_stage_async()

You can also attach an already opened stage with USD API to the UsdContext, like so:

   from pxr import Usd
   stage = Usd.Stage.Open(stage_url)

   # More setups to stage before it's attached to a UsdContext.
   ...

   result, error_str = await usd_context.attach_stage_async(stage)

Along with those async APIs, synchronous APIs are supported also without “_async” suffix. It’s recommended to use asynchronous APIs to avoid blocking main thread.

C++

In C++, you need to include header <omni/usd/UsdContext.h> to access UsdContext.

#include <omni/usd/UsdContext.h>

...
auto usdContext = omni::usd::UsdContext::getContext();
...

How to subscribe to Stage Events

Through the APIs of UsdContext, developers can also query status changes of the stage with omni.usd.UsdContext.get_stage_state(), and subscribe to event changes via creating a event stream subscription omni.usd.UsdContext.get_stage_event_stream():

Python

import omni.usd
import carb


def on_stage_event(event: carb.events.IEvent):
   if event.type == int(omni.usd.StageEventType.OPENING):
      ...
   elif event.type == int(omni.usd.StageEventType.OPENED):
      ...
   elif event.type == int(omni.usd.StageEventType.CLOSING):
      ...
   elif event.type == int(omni.usd.StageEventType.CLOSED):
      ...

usd_context = omni.usd.get_context()
subscription = usd_context.get_stage_event_stream().create_subscription_to_pop(
   on_stage_event, name="Example"
)

C++

#include <omni/usd/UsdContext.h>
#include <carb/events/EventsUtils.h>

...
auto usdContext = omni::usd::UsdContext::getContext();
auto stageStream = usdContext->getStageEventStream();
auto stageEvtSub = createSubscriptionToPop(stageStream.get(),
   [](carb::events::IEvent* e) {
      switch (static_cast<omni::usd::StageEventType>(e->type))
      {
      case omni::usd::StageEventType::eOpened:
         ...
         break;
      case omni::usd::StageEventType::eClosed:
         ...
         break;
      default:
         break;
      }
   },
   0, "Example"
);
...

You can refer to omni.usd.StageEventType for a full list of supported events.

How to Create Another UsdContext

Module omni.usd supports multiple UsdContexts so it can have different stages opened in addition to the default one, and also different Hydra Engines attached to render other viewports. UsdContext is indexed with unique name string, therefore you need to provide unique name string when you want to create/access specific UsdContext. You can refer to omni.usd.create_context() and omni.usd.destroy_context for creating/destroying a UsdContext. And you can get the context through omni.usd.get_context with name argument to access it.

Selections

UsdContext also provides interfaces to manage prim selections in a stage. Through which, you can set/query user selections with API, and also it provides event to detect selection changes. See omni.usd.Selection for more details.

Python

import omni.usd

context = omni.usd.get_context()
selection = context.get_selection()

...

# How to select multiple prims
# [...] is a list of prim paths in string type.
selection.set_selected_prim_paths([...], True)

...

# How to select/unselect single prim, where:
# select_or_unselect means if you want to select a prim or unselect a prim.
# clear_selected_or_not means if you want to clear all selected prims before this action.
selection.set_prim_path_selected(prim_path_in_str, select_or_unselect, True, clear_selected_or_not, True)

...

# How to clear all selected prims
selection.clear_selected_prim_paths()

...

# How to check if a prim is selected or not.
if selection.is_prim_path_selected(prim_path_in_str):
   ...

# How to get all selected prim paths.
prim_paths = selection.get_selected_prim_paths()

...

# How to select all prims with specific types, where [...] is a list of prim type names.
selection.select_all_prims([...])

C++

#include <omni/usd/UsdContext.h>
#include <carb/events/EventsUtils.h>

...
auto usdContext = omni::usd::UsdContext::getContext();
auto selection = usdContext->getSelection();
...

In order to subscribe to selection changes, you can refer to “How to subscribe to Stage Events” for reference.

Commands

Module omni.usd provides a set of pre-defined undoable USD commands to help other extensions to implement undo/redo workflow around USD. For the full list of commands supported, you can refer to omni.usd.commands. You can also refer to omni.kit.commands for the details of command system supported in Kit.

Utils

Module omni.usd extends several metadata for instructing UI implementation, and it provides encapsulated APIs for each access to those metadata. For example, you can instruct Stage Window to not show the specific prim, or you can instruct UI to avoid removing your prim. You can refer to omni.usd.editor for more details about all APIs provided.

Besides that, omni.usd provides a lot utils that encapsulate common USD operations that may be helpful for developers to use, which you can refer to API doc for reference.

Thread Safety

UsdStage access is not threadsafe, therefore, you should avoid authoring USD with multiple writers in Python as omni.usd doesn’t provide thread-safety APIs but exposes UsdStage handle. In C++, you need to ensure all write accesses are locked with USD lock (see omni::usd::UsdContext for more details.)

API Changes

Since Kit 106.0, old layer interface accessed through omni.usd.UsdContext.get_layers is removed which was deprecated since Kit 104.0. In order to access corresponding APIs, you’d have to refer omni.kit.usd.layers for more details.