Connect Sample¶

Overview¶
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

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.

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

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

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¶

- 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
- 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¶

- Additional Options (to silence warnings):
/wd4244 /wd4305
- 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
- Preprocessor Definitions:
- Debug
BOOST_ALL_DYN_LINK;NOMINMAX;TBB_USE_DEBUG=1
- Release
BOOST_ALL_DYN_LINK;NOMINMAX;TBB_USE_DEBUG=0
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.

- 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)
set BUILD_CONFIG=%1
set OUTPUT_PATH=%2
set RC_OPTS=/NP /NJH /NJS /NS /NC /NFL /NDL
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
OmniUSDReader.cpp¶
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 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 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;
exit(-1);
}
}
// Startup Omniverse
static bool startOmniverse()
{
// Register a function to be called whenever the library wants to print something to a log
omniClientSetLogCallback(
[](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
omniClientSetLogLevel(eOmniClientLogLevel_Info);
// 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;
startOmniverse();
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
stage.Reset();
omniClientShutdown();
}
Release Notes¶
104.1 Point Release¶
Samples
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 cloudfront.net 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