Loading USD#

Before rendering, load USD content into the renderer’s runtime stage. ovrtx supports three composition patterns:

  • Open a file path, URL, or inline USDA string as the root layer.

  • Compose a new inline root layer that sublayers an existing scene and authors additional prims such as cameras, RenderProducts, RenderVars, or labels.

  • Add removable referenced content under a path prefix after a root stage is already open.

Opening a Root Layer#

print(f"Opening {USD_URL}...", file=sys.stderr)
renderer.open_usd(USD_URL)
print("USD loaded.", file=sys.stderr)
// Load a USD layer into the renderer.
//
// As well as just passing a URI to an existing layer, we could pass a USDA
// string in order to compose a Stage at runtime. This can be very useful
// for dynamically creating the RenderProducts etc. that define the render
// output rather than editing the original layer to add them.
//
// A real application might want to load the USD layer and traverse it to
// find either existing RenderProducts, and/or Cameras and allow the user to
// select which one to render, and which RenderVars to output.
char const* usd_url = "https://omniverse-content-production.s3.us-west-2.amazonaws.com/Samples/Robot-OVRTX/robot-ovrtx.usda";

std::cerr << "Adding " << usd_url << " at root..." << std::endl;
ovrtx_enqueue_result_t enqueue_result =
    ovrtx_open_usd_from_file(renderer, {usd_url, strlen(usd_url)});

// This operation is asynchronous as loading the USD may take a long time.
// We'll just poll every 100ms till it's done.
ovrtx_op_wait_result_t wait_result;
result = ovrtx_wait_op(
    renderer, enqueue_result.op_index, ovrtx_timeout_t{0}, &wait_result);
if (check_and_print_error(result, "wait_op")) {
    ovrtx_destroy_renderer(renderer);
    return 1;
}
while (ovrtx_wait_op(renderer, enqueue_result.op_index, ovrtx_timeout_t{0},
                    &wait_result).status == OVRTX_API_TIMEOUT) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
std::cerr << "USD loaded." << std::endl;

Python open_usd blocks. Python open_usd_async and all C open calls are asynchronous and must be waited before using the loaded stage.

Inline Composition#

Use an inline root layer when an existing scene does not contain the render configuration, sensors, or semantic metadata the application needs. The inline root can sublayer the original scene and author additional prims without modifying the source asset.

(
    subLayers = [
        @../../data/ovrtx-test-base.usda@
    ]
)

def Camera "DocsCamera" (
    prepend apiSchemas = ["OmniSensorGenericCameraCoreAPI"]
)
{
}

def "Render"
{
    def RenderProduct "DocsCamera"
    {
        rel camera = </DocsCamera>
        rel orderedVars = [<LdrColor>]

        def RenderVar "LdrColor"
        {
            string sourceName = "LdrColor"
        }
    }
}
renderer.open_usd_from_string(f'''
#usda 1.0
(
    subLayers = [
        @{scene_path}@
    ]
)

def "Render" {{
    def RenderProduct "Camera" {{
        int2 resolution = (1920, 1080)
        rel camera = </Camera0>
        rel orderedVars = [<LdrColor>, <HdrColor>]

        def RenderVar "LdrColor" {{
            string sourceName = "LdrColor"
        }}

        def RenderVar "HdrColor" {{
            string sourceName = "HdrColor"
        }}
    }}
}}
''')

products = renderer.step(
    render_products={"/Render/Camera"},
    delta_time=1.0 / 60,
)
    std::string scene_path = get_test_data_dir() + "/simple_camera.usda";
    std::string usda = make_sublayer_usda(scene_path, R"usda(
def "Render" {
    def RenderProduct "Camera" {
        int2 resolution = (640, 480)
        rel camera = </Camera0>
        rel orderedVars = [<LdrColor>, <HdrColor>]

        def RenderVar "LdrColor" {
            string sourceName = "LdrColor"
        }

        def RenderVar "HdrColor" {
            string sourceName = "HdrColor"
        }
    }
}
)usda");
    ovrtx_enqueue_result_t enqueue_result = ovrtx_open_usd_from_string(renderer, {usda.c_str(), usda.size()});
    ASSERT_API_SUCCESS(enqueue_result.status);

    ovrtx_op_wait_result_t wait_result;
    result = ovrtx_wait_op(renderer, enqueue_result.op_index,
                           ovrtx_timeout_infinite, &wait_result);
    ASSERT_API_SUCCESS(result.status);
    ASSERT_NO_OP_ERRORS(wait_result);

References#

Use reference APIs when a root stage is already open and you want to add content under a new path prefix, then later remove it by handle.

handle = renderer.add_usd_reference(str(reference_file), "/World/LoadedBase")
prims = renderer.query_prims(attribute_filter_mode=ovrtx.AttributeFilterMode.NONE)
assert "/World/LoadedBase" in prims
assert "/World/LoadedBase/KnownChild" in prims

renderer.remove_usd(handle)
prims = renderer.query_prims(attribute_filter_mode=ovrtx.AttributeFilterMode.NONE)
assert "/World/LoadedBase" not in prims
assert "/World/LoadedBase/KnownChild" not in prims
ovrtx_usd_handle_t usd_handle{};
ovrtx_enqueue_result_t eq = ovrtx_add_usd_reference_from_file(
    renderer_,
    {reference_path_str.c_str(), reference_path_str.size()},
    ovx_str("/World/LoadedBase"),
    &usd_handle);
ASSERT_API_SUCCESS(eq.status);
docs_wait_no_errors(renderer_, eq.op_index);

std::set<std::string> paths = docs_query_all_paths(renderer_);
ASSERT_TRUE(paths.count("/World/LoadedBase"));
ASSERT_TRUE(paths.count("/World/LoadedBase/KnownChild"));

eq = ovrtx_remove_usd(renderer_, usd_handle);
ASSERT_API_SUCCESS(eq.status);
docs_wait_no_errors(renderer_, eq.op_index);

Inline referenced content must have a defaultPrim because the reference is composed below the requested path prefix.

Time-Sampled USD#

For animated USD scenes, re-evaluate time-sampled attributes at a stage time. The API takes seconds and converts to USD time codes using the stage metadata.

# update_from_usd_time_async takes seconds, not USD timecodes — the
# runtime converts via the stage's timeCodesPerSecond metadata.
# .wait() resolves once time-sampled attributes have been re-evaluated.
renderer.update_from_usd_time_async(t_seconds).wait()

Resetting the Stage#

reset_stage clears all USD content from the runtime stage. Python exposes reset_stage and reset_stage_async; C uses ovrtx_reset_stage(). Opening a new root layer replaces the previous root.

Authored Attribute Population#

By default, the runtime populates supported schema attributes. To read or write generic custom authored attributes, an inline root layer can set customLayerData.populateAllAuthoredAttributes = true. Use this only when needed: large assets may contain many authored properties that the application will never use.