Connect Sample

The stage created by the HelloWorld Sample


Build your own NVIDIA Omniverse Connector with prebuilt source code samples that use Pixar USD and Omniverse Client Library APIs.

Run build.bat to download the USD and Omniverse dependencies, generate the Visual Studio solution file, and build it.

If interested in what dependencies are necessary to build your own Connector, examine either the premake.lua build configuration file or the output project files in the _compiler folder.

Omni CLI

A command line utility to manage files on a Nucleus Server (omnicli.bat).

This program was initially created to exercise most of the Omniverse Client Library API, but has grown to be a useful utility to interact with Nucleus servers. Typing help will produce a menu that shows the many functions available. Among the most useful are the move/copy functions which can transfer data to and from servers.

HelloWorld (C++)

A sample program that creates a USD stage on a Nucleus server (run_sample.bat).

The sample demonstrates how to:

  • connect to an Omniverse server

  • create a USD stage

  • create a physics scene to define simulation parameters

  • create a polygonal box and add it to the stage and make it a dynamic rigid

  • create a cube and add it to the stage and make it a dynamic rigid

  • create a quad and add it to the stage and make it a collider

  • upload an MDL material and its textures to an Omniverse server

  • bind an MDL and USD Preview Surface material to the box

  • add a distant and dome light to the stage

  • create Nucleus checkpoints

  • move and rotate the box with live updates

  • disconnect from an Omniverse server

  • print verbose Omniverse logs

  • open an existing stage and find a mesh to do live edits

HelloWorld (Python)

A sample program with the same functionality of the C++ HelloWorld sample written in Python (run_py_sample.bat).

OmniUSDAWatcher (C++)

The Omniverse USDA Watcher is a command line program that keeps an updated USDA file on local disk that maps to a USD resident on a Nucleus server.

It takes two arguments, the USD stage URL to watch and the output USDA stage URL:

  • Acceptable forms

    • URL: omniverse://localhost/Users/test/helloworld.usd

    • URL: C:\USD\helloworld.usda

    • A relative path based on the CWD of the program (helloworld.usda)

The “watcher” demonstrates how to:

  • Initialize Omniverse

    • Set the Omniverse Client log callback (using a lambda)

    • Set the Omniverse Client log level

    • Initialize the Omniverse Client library

    • Register a connection status callback

  • Set the USD stage URL as live

  • Open the USD stage

  • Create and register the Sdf layer reload, layer change, and USD notice listeners

  • Subscribe to file changes with omniClientStatSubscribe

  • Start a thread that loops, receiving live changes from other clients

    • When the stage is modified it’s written out to the specified USDA

  • The main thread loops on keyboard input, waiting for a ‘q’ or ESC

  • Cleanup the callbacks (unsubscribe and revoke)

  • Destroy the stage object

  • Shutdown the Omniverse Client library

For example, to monitor the stage that the HelloWorld sample creates by default: run_omniUsdaWatcher.bat omniverse://localhost/Users/test/helloworld.usd C:\USD\helloworld.usda

OmniUsdaWatcher in action

OmniSimpleSensor (C++)

The Omniverse Simple Sensor example demonstrates how to connect external input to a USD in Nucleus. This could effectively be a large number of inputs that report current values for IoT sensors or could locations from robots and a real-time synchronization of the data in the virtual world is desired.

It takes three arguments, the Nucleus server path, the number of inputs and a timeout value.

run_OmniSimpleSensor.bat  <server path> <number of inputs> <timeout>

  • Acceptable forms
    • Server Path: omniverse://localhost/Users/test (a location on a Nucleus server)

    • Number of Inputs: 4 (integer value of 1 to any number)

    • Timeout: -1 or 20 (-1 is for infinity to run until killed, otherwise a number in seconds)

    • Example - run_OmniSimpleSensor omniverse://localhost/Users/test 27 -1

There are two parts to this project.

OmniSimpleSensor will build a USD with a number of boxes (meshes) on one layer.

  • Initialize Omniverse

  • Check for an existing SimpleSensorExample.usd stage at the <server path> location, if it exists, delete it

  • Create SimpleSensorExample.usd at <server path>

  • Build a simple array of box meshes, starting with /World/Box_0 then /World/Box_1 and so on

  • Save the USD

  • Destroy the stage object

  • Shutdown the Omniverse Client library

OmniSensorThread is then started for each ‘input’ specified in the command line.

  • Initialize Omniverse

  • Open SimpleSensorExample.usd at <server path>

  • Find the box mesh in USD this process will change

  • Create a worker thread to update the box’s color every 300ms

  • In the main loop, wait until the timeout occurs, then
    • Stop the worker thread

    • Destroy the stage object

    • Shutdown the Omniverse Client library

For example, if 6 inputs are asked for then there will be 6 OmniSensorThread processes running, independently of each other. The OmniSensorThread will launch a thread that will update the color of its assigned box at a given frequency (300ms in the code, but this can be altered). Opening the stage (look for SimpleSensorExample.usd in the Nucleus location specified) and turning on Live mode in Create or View, the boxes will be changing colors at some regular intervals.

This project can easily be extended to change the transform of the boxes or to add some metadata with a custom string attached to the USD or do change visibility states.

Some things to note here:

  • Using separate processes for each input, allows the USD to be changed independently

  • This example could be re-written to have one main process and a bunch of worker threads launched for each input. In this case, there would be a need to use a mutex when writing data to Nucleus through one Omni Client Library instance (there is one instance per process). This will ensure that the writing to USD via the Omni Client Library resource is dedicated. Keeping the mutex around the smallest bit of code writing to USD is recommended in this case to prevent thread starvation (especially when the frequency of input is high).

  • Reading USD via Omni Client Library does not have this issue and multiple threads in the same process can read from a USD, even the same layer in USD, without a mutex.

Connection Paths of the Simple Sensor Example


To find where the Connect Sample is installed, find the Connect Sample under the Library:Connectors tab, click the hamburger icon and select “Settings”:

Go to the Settings from the hamburger menu button

Clicking the folder icon next to the Install Path will open a file browser window to where it is installed:

Click the folder icon to open the install location of the Connect Sample

Configuring MSVC (Advanced)

When prebuild.bat is executed (by itself or through build.bat) a version of the Microsoft Visual Studio Compiler and the Windows 10 SDK are downloaded and referenced by the generated Visual Studio projects. If a user wants the projects to use an installed version of Visual Studio then run configure_win_buildtools.bat first. This script should find vswhere.exe and then use it to discover which MSVC compiler to use. If it does not you can edit the deps/host-deps.packman.xml file’s buildtools source path to the folder on your PC which contains the VC subfolder (normally something like C:/Program Files (x86)/Microsoft Visual Studio/2017/BuildTools).

Changing the Windows 10 SDK (Advanced)

If a user wants the generated projects to use a different Windows 10 SDK than what is downloaded then the configure_win_buildtools.bat file will automatically search for one using the winsdk.bat Microsoft tool and insert the correct paths into the deps/host-deps.packman.xml file. If the winsdk.bat file doesn’t do what is required, edit these fields in the deps/host-deps.packman.xml file:

  • winsdk

  • winsdk_bin

  • winsdk_include

  • winsdk_lib

Note that an installed Windows SDK will have the actual version in all of these paths, for example include/10.0.17763.0 rather than just include

Creating a Windows USD App from the Omniverse Connect Sample

This section describes how to create a simple application that will open a USD stage located on an Omniverse Nucleus server based on the USD and Omniverse Client Libraries retrieved from the Connect Sample. Once the stage is open it will simply report the stage up-axis, the stage linear units, and list all of the prim node paths.

Dependencies for Omniverse Client Library and USD

Both the Omniverse Client Library and NVIDIA’s modified USD SDK are required, so the first thing to do is to copy them into the project structure of the simple app.

From the Connect Sample root folder, these two folders should be copied (after the dependencies are fetched using either prebuild.bat or build.bat):

  • _build\target-deps\nv_usd

  • _build\target-deps\omni_client_library

Both of these dependencies contain symbolic links, so care must be taken when copying them into the simple app’s folders. robocopy (distributed with Windows 10) does a good job of deep-copying symbolic links. The deps folder will hold the USD and Client Library dependencies for the application. Here are a couple command lines that can be run from within the Connect Sample’s root folder, note that in this case the simple project is located in the X:\tmp\OmniUSDReader directory:

  • robocopy /S _build\target-deps\nv_usd X:\tmp\OmniUSDReader\deps\nv_usd

  • robocopy /S _build\target-deps\omni_client_library X:\tmp\OmniUSDReader\deps\omni_client_library

Project Settings

Because this application uses USD that means it uses Boost and TBB which require libraries, preprocessor definitions, and additional options. Also note that we only provide the 64 bit x64 platform binaries, so don’t try to build for the 32 bit platform in Visual Studio when you generate a new console project (for this example at least).

Linker Settings

Visual Studio Linker Options
  1. Additional Library Directories:
    • Debug
      • deps\nv_usd\debug\lib;deps\omni_client_library\debug

    • Release
      • deps\nv_usd\release\lib;deps\omni_client_library\release

  2. Additional Dependencies:
    • Debug
      • ar.lib;arch.lib;gf.lib;js.lib;kind.lib;pcp.lib;plug.lib;sdf.lib;tf.lib;trace.lib;usd.lib;usdGeom.lib;vt.lib;work.lib;usdShade.lib;usdLux.lib;omniclient.lib;python37.lib;boost_python37-vc141-mt-gd-x64-1_68.lib

    • Release
      • ar.lib;arch.lib;gf.lib;js.lib;kind.lib;pcp.lib;plug.lib;sdf.lib;tf.lib;trace.lib;usd.lib;usdGeom.lib;vt.lib;work.lib;usdShade.lib;usdLux.lib;omniclient.lib;python37.lib;boost_python37-vc141-mt-x64-1_68.lib

    • Note that the boost python library is the only difference between debug and release

C/C++ Compiler Settings

Visual Studio C++ Options
  1. Additional Options (to silence warnings):
    • /wd4244 /wd4305

  2. Additional Include Directories:
    • Debug
      • deps\nv_usd\debug\include;deps\omni_client_library\include

    • Release
      • deps\nv_usd\release\include;deps\omni_client_library\include

  3. Preprocessor Definitions:
    • Debug

    • Release

Post-build Event to Copying Runtime Dependencies

There are a lot of runtime dependencies, to make things easy they are simply copied to the same folder as the output executable. A batch file that runs after the app is built makes this convenient and free of errors.

Visual Studio C++ Options
  1. Post-Build Event:
    • Debug
      • scripts\copy_binary_deps.bat debug $(OutputPath)

    • Release
      • scripts\copy_binary_deps.bat release $(OutputPath)

The copy_binary_deps.bat script is run after each build and puts the runtime dependencies in the correct place. It should be copied into the project’s scripts folder:

@echo off
:: copy the USD and OmniClient libs to the $(OutputPath)
:: parameters:
:: 1. debug or release
:: 2. $(OutputPath)


echo Copying deps\nv_usd\%BUILD_CONFIG%\lib contents to %OUTPUT_PATH%
robocopy /S deps\nv_usd\%BUILD_CONFIG%\lib %OUTPUT_PATH% %RC_OPTS%

echo Copying deps\omni_client_library\%BUILD_CONFIG% contents to %OUTPUT_PATH%
robocopy /S deps\omni_client_library\%BUILD_CONFIG% %OUTPUT_PATH% %RC_OPTS%

exit /B 0

Simple App Overview

The application performs a few simple things:

  • Expects one argument, the path to a USD stage

    • Acceptable forms:

      • omniverse://localhost/Users/test/helloworld.usd

      • C:\\USD\\helloworld.usd

      • A relative path based on the CWD of the program (helloworld.usd)

    • Initialize Omniverse

      • Set the Omniverse Client log callback

      • Set the Omniverse Client log level

      • Initialize the Omniverse Client library

      • Register an Omniverse Client status callback

    • Open the USD stage

    • Print the stage’s up-axis

    • Print the stage’s linear units, or “meters per unit” setting

    • Traverse the stage prims and print the path of each one

    • Destroy the stage object

    • Shutdown the Omniverse Client library


Here’s a copy of the simple OmniUSDReader app. The intent is to eventually distribute it with the Connect Sample, but it’s listed here to make it readily available:

# Copyright 2021 NVIDIA Corporation
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.

# The "OmniUSDReader" application performs a few simple things:
#      * Expects one argument, the path to a USD stage
#              * Acceptable forms:
#                      * omniverse://localhost/Users/test/helloworld.usd
#                      * C:\USD\helloworld.usd
#                      * A relative path based on the CWD of the program (helloworld.usd)
#      * Initialize Omniverse
#              * Set the Omniverse Client log callback (using a lambda)
#              * Set the Omniverse Client log level
#              * Initialize the Omniverse Client library
#              * Register an Omniverse Client status callback (using a static function)
#      * Open the USD stage
#      * Print the stage’s up-axis
#      * Print the stage’s linear units, or “meters per unit” setting
#      * Traverse the stage prims and print the path of each one
#      * Destroy the stage object
#      * Shutdown the Omniverse Client library

#include <iostream>
#include <iomanip>
#include "OmniClient.h"
#include "pxr/usd/usd/stage.h"
#include "pxr/usd/usd/primRange.h"
#include "pxr/usd/usdGeom/metrics.h"

using namespace pxr;

static void OmniClientConnectionStatusCallbackImpl(void* userData, const char* url, OmniClientConnectionStatus status) noexcept
    std::cout << "Connection Status: " << omniClientGetConnectionStatusString(status) << " [" << url << "]" << std::endl;
    if (status == eOmniClientConnectionStatus_ConnectError)
        // We shouldn't just exit here - we should clean up a bit, but we're going to do it anyway
        std::cout << "[ERROR] Failed connection, exiting." << std::endl;

// Startup Omniverse
static bool startOmniverse()
    // Register a function to be called whenever the library wants to print something to a log
        [](char const* threadName, char const* component, OmniClientLogLevel level, char const* message)
            std::cout << "[" << omniClientGetLogLevelString(level) << "] " << message << std::endl;

    // The default log level is "Info", set it to "Debug" to see all messages

    // Initialize the library and pass it the version constant defined in OmniClient.h
    // This allows the library to verify it was built with a compatible version. It will
    // return false if there is a version mismatch.
    if (!omniClientInitialize(kOmniClientVersion))
        return false;

    omniClientRegisterConnectionStatusCallback(nullptr, OmniClientConnectionStatusCallbackImpl);

    return true;

// The program expects one argument, a path to a USD file
int main(int argc, char* argv[])
    if (argc != 2)
        std::cout << "Please provide an Omniverse stage URL to read." << std::endl;
        return -1;

    std::cout << "Omniverse USD Stage Traversal: " << argv[1] << std::endl;


    UsdStageRefPtr stage = UsdStage::Open(argv[1]);
    if (!stage)
        std::cout << "Failure to open stage.  Exiting." << std::endl;
        return -2;

    // Print the up-axis
    std::cout << "Stage up-axis: " << UsdGeomGetStageUpAxis(stage) << std::endl;

    // Print the stage's linear units, or "meters per unit"
    std::cout << "Meters per unit: " << std::setprecision(5) << UsdGeomGetStageMetersPerUnit(stage) << std::endl;

    // Traverse the stage and return the first UsdGeomMesh we find
    auto range = stage->Traverse();
    for (const auto& node : range)
        std::cout << node.GetPath() << std::endl;

    // The stage is a sophisticated object that needs to be destroyed properly.
    // Since stage is a smart pointer we can just reset it


Release Notes

104.1 Point Release

  • Samples

    • Added physics to HelloWorld sample to showcase UsdPhysics usage.

      Press play to see physics working in the sample
    • Added the file hash to the stat output in OmniCLI

    • Added “cver” command to print client version

    • Change the live rotations from ZYX to XYZ and all xform ops to double3

  • Omniverse Client Library

    • 1.17.4

      • OM-47554: Downgrade some “Error” messages during auth to “Verbose”

        • We attempt to connect using 3 different methods, and it’s normal for 2 of them to fail. This avoids confusing users with error messages for a connection that ultimately succeeds.

      • OM-48252: Lower required “list2” version, to allow connecting to servers running Nucleus 112.0.

    • 1.17.3

      • CC-357: Fixed a deadlock that could occur when a python file status callback is being unregistered on one thread while another thread is simultaneously trying to call that file status callback

      • CC-367: Allow stat & list using URLs

      • OM-45178: Print extended error message when Token.subscribe fails

      • OM-45887: Enable extra connection logging

      • CC-384: Remove support for Nucleus 107, 109, and 110

      • CC-366: Update OpenSSL to avoid a security vulnerability

    • 1.17.2

      • CC-32: Fixed a crash that could happen on disconnect

      • OM-43009: Removed “stop” from list of required capabilities, to discover newer servers which don’t advertise that capability

      • CC-236: Add support for checkpoint change notification

      • CC-245: Fixed a deadlock that could occur rarely when connection failed.

    • 1.17.1

      • CC-228: subscription based authentication using ‘nonce’

      • CC-231: Discover API server using minimum required capabilities rather than all capabilites

      • CC-229: Fixed a case where the client library would not connect to Nucleus securely

    • 1.17.0

      • CC-7: Add shutdown guard to omniclient::Core

    • 1.16.0

      • OM-39826: Prevent copying of channels from nucleus servers to other providers

      • OM-38687: Fix crash when shutdown with an outstanding stat subscription

      • OM-37095: Use omniClientWait in blocking python binding functions

      • OM-38761: Fix ResolveSubscribe to handle more invalid search paths

      • OM-39746: Support stat(‘/’) on S3 buckets. S3 API does not support stat() on root, but we can fill in the gaps

    • 1.15.0

      • OM-39614: Fixed a case where pings would not report a connection error

      • OM-36524: update connection library to prevent using Nucleus Cache when accessing localhost servers

      • OM-37061: Fix crash if a request is started after it is stopped

      • OM-34916: Map MountExistsUnderPath error to ErrorNotSupported

      • OM-38761: Fixed StatImpl::beginWatch to always call the provided callback, even when the uri to watch is invalid.

      • OM-39367: Removed “fast locked updates” because it’s fundamentally broken. Removes omniUsdLiveLock & omniUsdLiveUnlock

      • OM-23042: If the relativePath starts with “./” then don’t use search paths

    • 1.14.0

    • OM-38721: Added function omniClientGetLocalFile which returns the local filename for a URL

      • If the input URL is already a local file, it is returned without error

      • If the remote file has not yet been downloaded to cache, it is downloaded before returning

      • Python bindings are “get_local_file” “get_local_file_async” and “get_local_file_with_callback”

    • OM-38816: Added environment variable OMNI_DEPLOYMENT which can override the deployment sent to discovery

    • OM-37061: Early exit from callback if cacheEntry weak_ptr is expired, correct creation of cacheEntry ownership

    • 1.13.25

      • OM-34145: Fix omniClientCopy to not infinitely copy when copying a directory into a subdirectory of itself.

    • 1.13.24

      • OM-38028: Update Brotli, OpenSSL, and libcurl versions

    • 1.13.23

      • OM-37701: Fix FetchToLocalResolvedPath to work with SdfFileFormat arguments

    • 1.13.22

      • OM-37276: Use latest idl.cpp to pickup SSL cert directory location fixes

    • 1.13.21

      • OM-36064 & OM-36306: Fix crash in listSubscribe on disconnect

    • 1.13.20

      • OM-37054: Fix incorrect search order according to PBR specification

      • OM-36511: Add python bindings set_authentication_message_box_callback & authentication_cancel

103.1 Point Release

  • Samples

    • Added omniUsdReader, a very simple program for build config demonstration that opens a stage and traverses it, printing all of the prims

    • Added omniUsdaWatcher, a live USD watcher that outputs a constantly updating USDA file on disk

    • Updated the nv-usd library to one with symbols so the Visual Studio Debug Visualizers work properly

  • Omniverse Client Library
    • Still using 1.13.19

102.1 Point Release

  • Samples

    • OM-31648: Add a windows build tool configuration utility if the user wants to use an installed MSVC and the Windows SDK

    • Add a dome light with texture to the stage

    • OM-35991: Modify the MDL names and paths to reduce some code redundancy based on a forum post

    • Add Nucleus checkpoints to the Python sample

    • Avoid writing Nucleus checkpoints when live mode is enabled, this isn’t supported properly

    • OM-37005: Fix a bug in the Python sample batch file if the sample was installed in a path with spaces

    • Make the /Root prim the defaultPrim

    • Update Omniverse Client Library to 1.13.19

  • Omniverse Client Library

    • 1.13.19
      • OM-36925: Fix omniClientMakeRelative(“omni://host/path/”, “omni://host/path/”);

    • 1.13.18
      • OM-25931: Fixed some issues around changing and calling the log callback to reduce hangs.

      • OM-36755: Fixed possible use-after-delete issue with set_log_callback (Python).

    • 1.13.17
      • OM-34879: Hard-code “mdl” as “not a layer” to work around a problem that happens if the “usdMdl” plugin is loaded

    • 1.13.16
      • OM-36756: Fix crash that could happen if two threads read a layer at the exact same time.

    • 1.13.15
      • OM-35235: Fix various hangs by changing all bindings to release the GIL except in very specific cases.

    • 1.13.14
      • OM-34879: Fix hang in some circumstances by delaying USD plugin registration until later

      • OM-33732: Remove USD diagnostic delegate

    • 1.13.13
      • OM-36256: Fixed S3 provider from generating a bad AWS signature when Omni Cache is enabled

    • 1.13.12
      • OM-20572: Fixed setAcls

    • 1.13.11
      • OM-35397: Fixed a bug that caused Linux’s File Watcher Thread to peg the CPU in some cases.

    • 1.13.10
      • OM-32244: Fixed a very rare crash that could occur when reading a local file that another process has locked

    • 1.13.9
      • OM-35050: Fixed problem reloading a non-live layer after it’s been modified.

    • 1.13.8
      • OM-34739: Fix regression loading MDLs introduced in * 1.13.3

      • OM-33949: makeRelativeUrl prepends “./” to relative paths

      • OM-34752: Make sure local paths are always using “” inside USD on Windows

    • 1.13.7
      • OM-34696: Fixed bug when S3 + cloudfront + omni cache are all used

    • 1.13.6
      • OM-33914: Fixed crash when accessing http provider from multiple threads simultaneously

    • 1.13.5
      • OM-26039: Fixed “Restoring checkpoint while USD stage is opened live wipes the content”

      • OM-33753: Fixed “running massive amounts of live edits together causes massive amounts of checkpoints”

      • OM-34432: Fixed “[Create] It will lose all data or hang Create in live session”
        • These were all the same underlying issue: When a layer is overwritten in live mode it was cleared and set as ‘dirty’ which would cause the next “Save()” (which happens every frame in live mode) to save the cleared layer back to the Omniverse server.

    • 1.13.4
      • OM-31830: omniClientCopy() with HTTP/S3 provider as source

      • OM-33321: Use Omni Cache 2.4.1+ new reverse proxy feature for HTTPS caching

    • 1.13.3
      • OM-33483: Don’t crash when trying to save a layer that came from a mount

      • OM-27233: Support loading non-USD files (abc, drc, etc)

      • OM-4613 & OM-34150: Support saving usda files as ascii
        • Note this change means live updates no longer work with usda files (though they technically never did – it would silently convert them to usdc files).

101.1 Point Release

  • Add Linux package for the Omniverse Launcher

  • Add a Python 3 Hello World sample

  • Update the Omniverse Client Library to 1.13

  • Update to Python 3.7

  • Add a Nucleus Checkpoint example

  • Add the ability to create/access a USD stage on local disk in the Hello World sample

100.2 Update

  • Update the Omniverse Client Library fix an issue with overlapping file writes

100.1 Point Release

  • First release

  • HelloWorld sample that demonstrates how to:

    • connect to an Omniverse server

    • create a USD stage

    • create a polygonal box and add it to the stage

    • upload an MDL material and its textures to an Omniverse server

    • bind an MDL and USD Preview Surface material to the box

    • add a light to the stage

    • move and rotate the box with live updates

    • print verbose Omniverse logs

    • open an existing stage and find a mesh to do live edits

  • OmniCLI sample that exercises most of the Omniverse Client Library API