Getting Started with Connect SDK

Try the Connect Samples

The best way to get started with the Connect SDK is to try out the Connect Samples. These are simple connectors built with the Connect SDK and they showcase many features and key concepts of the SDK. You can execute the samples to try them out, learn from the source code used in the samples, and modify the samples to experiment working with the Connect SDK for yourself.

Get the Samples

The Connect Samples are available from the Connect Samples Github repository. You can clone the repository or download the source as a zip file.

Build

To try the samples you will need to build the samples from source. The included build scripts make it easy.

This project requires “make” and “g++”.

  1. Open a terminal.

  2. To obtain “make” type sudo apt install make (Ubuntu/Debian), or yum install make (CentOS/RHEL).

  3. For “g++” type sudo apt install g++ (Ubuntu/Debian), or yum install gcc-c++ (CentOS/RHEL).

  4. Use the provided build script to download all other dependencies (e.g USD), create the Makefiles, and compile the code:

    ./repo.sh build
    

Use the provided build script to download all dependencies (e.g USD), create the projects, and compile the code:

.\repo.bat build

Run

Once you have built the samples, you can run their executables to try them.

Use any of the run_*.sh scripts (e.g. ./run_hello_world.sh) to execute each program with a pre-configured environment.

Use the --help flag for each of the sample executables to learn more about the optional arguments that they accept. (e.g. ./run_hello_world.sh --help)

Use any of the run_*.bat scripts (e.g. .\run_hello_world.bat) to execute each program with a pre-configured environment.

Use the --help flag for each of the sample executables to learn more about the optional arguments that they accept. (e.g. .\run_hello_world.bat --help)

See also the Connect Samples README for more detailed descriptions and documentation about the individual samples.

Experiment

Once you have oriented yourself with the samples that interest you, try modifying the source code in the source/ directory of the repository to experiment with the SDK. Once you’ve made your change, just repeat the Build and Run steps in this guide and test out your change.

Proceed to the next section, to learn how you can start building your own connector.

Integrate Connect SDK and Build a Connector

The best way to get started with OpenUSD and the Omniverse Connect SDK is to create a simple standalone application.

This section will teach you how to create an application that opens a USD stage located on an Omniverse Nucleus server (or local disk), reports basic stage configuration details, and lists all of the UsdPrim paths.

Note that some Connectors (or Converters) are designed as standalone applications, while others are plugins that runs in the context of an existing content creation tool. See the Plugins vs Applications guide for some suggestions on which to build.

This walkthrough will use these tokens:

  • $project_root - the base directory where the project application is located

  • $config - the build configuration (debug or release)

  • $platform - the platform (linux-x86_64 or windows-x86_64)

“Install” the Connect SDK

Assembling the minimal requirements for the Connect SDK can be complicated, so there is an install_sdk script that developers run to gather everything into one _install folder. This folder can then be copied into the project structure of the developer’s application. Note that the install_sdk script may be run from either the Connect Samples or the Connect SDK root directory, it is provided with both repositories.

Running these commands will generate the _install folder for both debug and release configurations and deep copy them to wherever the sample project is located. Note that if running the install script from the Connect Samples, it is necessary to build them first:

./repo.sh build
./repo.sh install_sdk --config release
./repo.sh install_sdk --config debug
cp -Lr _install $project_root/connect-sdk
repo.bat build
repo.bat install_sdk --config release
repo.bat install_sdk --config debug
robocopy /s _install $project_root\connect-sdk > NUL
_install
├───target-deps <----------- build dependencies
│   ├───carb_sdk_plugins
│   ├───omni_client_library
│   ├───omni_connect_sdk
│   ├───omni_transcoding
│   ├───omni_usd_resolver
│   ├───python
│   ├───usd
├───$platform/$config <----- runtime dependencies ($CARB_APP_PATH)
│   ├───config
│   ├───lib
│   ├───plugins
│   ├───python

This _install folder will be copied into $project_root/connect-sdk for this walkthrough. Note that the target-deps folder contains soft links on Linux and junctions on Windows, so any time it is copied, it requires deep copy commands or options.

For more details on choosing build flavors & features, or different versions of the SDK, see the repo_install_sdk documentation.

Runtime Dependencies

The install_sdk tool will assemble the exact runtime requirements based on the build flavor you have selected, so the easiest approach is to copy the file tree that it generated.

There is some flexibility however. For more thorough details about how to deploy the runtime dependencies for an application or plugin using the Connect SDK, see the detailed runtime requirements section.

Configuring the Carbonite Framework

The Omniverse Carbonite SDK is the foundational software layer for Omniverse applications, microservices, tools, plugins, Connectors, and SDKs.

Since the Connect SDK uses Carbonite internally, Connectors built with it must set an environment variable called $CARB_APP_PATH. This is typically accomplished in a bootstrap shell script or within the application itself. It should not be done at the system level as it needs to be application specific.

In this example, the environment variable $CARB_APP_PATH will be set to a folder called connect-sdk/$platform/$config and will contain the Carbonite plugins folder, the TOML configuration files, and all of the required runtime dependencies of the application.

Configuring TOML Files

The Connect SDK requires a configuration TOML file to be located in $CARB_APP_PATH/config/omni.connect.client.toml. In this example, only the application and client names and versions are required. Create this file in both the debug and release $CARB_APP_PATH/config directories:

# $project_root/connect-sdk/$platform/$config/config/omni.connect.client.toml
[app]
name = "GettingStarted"
version = "1.0"

["omni.connect.core".client]
name = "UsdTraverse"
version = "1.0"

There are many more possibilities for Settings and Configuration once we are past the basics.

Sample Program

The application performs a few simple things with OpenUSD and the Connect SDK:

  • 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 the Connect SDK

    • 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

    • If the prim is xformable then print its position

It is included here to copy into a UsdTraverse.cpp file within $project_root

// SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: MIT
//
#include <omni/connect/core/Core.h>
#include <omni/connect/core/XformAlgo.h>

#include <pxr/usd/usd/primRange.h>
#include <pxr/usd/usd/stage.h>
#include <pxr/usd/usdGeom/metrics.h>
#include <pxr/usd/usdGeom/xformable.h>

#include <iostream>

// Declare the Omniverse globals & default log channel
OMNI_APP_GLOBALS("UsdTraverse", "Getting started guide to using the Connect SDK for USD stage traversal");

// 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;

    // Acquire the Carbonite Framework and start the Connect SDK core module
    OMNICONNECTCORE_INIT();

    // Check that the SDK core actually initialized properly
    if (!omni::connect::core::initialized())
    {
        return -1;
    }

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

    // Print the stage metadata metrics
    std::cout << "Stage up-axis: " << pxr::UsdGeomGetStageUpAxis(stage) << std::endl;
    std::cout << "Meters per unit: " << UsdGeomGetStageMetersPerUnit(stage) << std::endl;

    // Traverse the stage, print all prim names, print transformable prim positions
    pxr::UsdPrimRange range = stage->Traverse();
    for (const auto& prim : range)
    {
        std::cout << prim.GetPath();

        if (pxr::UsdGeomXformable(prim))
        {
            pxr::GfTransform xform = omni::connect::core::getLocalTransform(prim);
            std::cout << ":" << xform.GetTranslation();
        }
        std::cout << std::endl;
    }
}

Build Configuration

Linux

For Linux, all of the build configuration settings are described in the Makefile included here:

# SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: MIT

# This makefile is a simple example for a Connector, application, or converter for including, linking, and executing with
# OpenUSD and the Connect SDK
#
# By default it will build against the release version of OpenUSD, to build against the debug version run `make CONFIG=debug`.

# The expectation is that USD, Connect SDK, and other dependencies are present in the `./connect-sdk/target-deps` directory
BOOSTVER = boost-1_78
DEPSDIR = $(CURDIR)/connect-sdk/target-deps
PYTHONVER = python3.10
PROGRAMNAME = UsdTraverse

ifndef CONFIG
	CONFIG=release
endif

ifndef TARGETDIR
	TARGETDIR = $(CURDIR)/$(CONFIG)
endif

# Debug vs. Release differences
ifeq ($(CONFIG),debug)
	CONFIG_DEFINES += -g -DDEBUG -O0 -DTBB_USE_DEBUG=1
else ifeq ($(CONFIG),release)
	CONFIG_DEFINES += -DNDEBUG -O2
endif

# ABI Settings
ifndef ABI_DEFINES
	ABI_DEFINES = -D_GLIBCXX_USE_CXX11_ABI=0 -std=c++17
endif

# Ignored Warnings
ifndef IGNORED_WARNINGS
	IGNORED_WARNINGS = -Wno-deprecated
endif

# Include search directories
 OMNI_USD_INCLUDE_DIRS = \
 -isystem $(DEPSDIR)/carb_sdk_plugins/include \
 -isystem $(DEPSDIR)/omni_connect_sdk/$(CONFIG)/include \
 -isystem $(DEPSDIR)/usd/$(CONFIG)/include \
 -isystem $(DEPSDIR)/usd/$(CONFIG)/include/$(BOOSTVER)

# USD libs (most of these not required, but this is a proper set for a fully featured Connector)
USD_LIBS = \
 -lboost_python310 \
 -lusd_ar \
 -lusd_arch \
 -lusd_gf \
 -lusd_js \
 -lusd_kind \
 -lusd_pcp \
 -lusd_plug \
 -lusd_sdf \
 -lusd_tf \
 -lusd_trace \
 -lusd_usd \
 -lusd_usdGeom \
 -lusd_usdLux \
 -lusd_usdShade \
 -lusd_usdUtils \
 -lusd_vt \
 -lusd_work

OMNI_LIBS = \
 -lcarb \
 -lomni_connect_core \
 -lomni_transcoding \
 -lomni_usd_resolver \
 -lomniclient

# Library dependency directories
 OMNI_USD_LIB_DIRS = \
 -L$(DEPSDIR)/carb_sdk_plugins/_build/linux-x86_64/$(CONFIG) \
 -L$(DEPSDIR)/omni_connect_sdk/$(CONFIG)/lib \
 -L$(DEPSDIR)/omni_transcoding/$(CONFIG)/lib \
 -L$(DEPSDIR)/omni_usd_resolver/$(CONFIG) \
 -L$(DEPSDIR)/omni_client_library/$(CONFIG) \
 -L$(DEPSDIR)/usd/$(CONFIG)/lib

# Python specifics
ifndef PYTHON_INCLUDE_DIR
	PYTHON_INCLUDE_DIR = -isystem $(DEPSDIR)/python/include/$(PYTHONVER)
endif

ifndef PYTHON_LIB
	PYTHON_LIB = -l$(PYTHONVER)
endif

ifndef PYTHON_LIB_DIR
	PYTHON_LIB_DIR = -L$(DEPSDIR)/python/lib
endif

# Common flags
CXXFLAGS += $(CONFIG_DEFINES) $(ABI_DEFINES) $(IGNORED_WARNINGS) -m64 -DTBB_SUPPRESS_DEPRECATED_MESSAGES
INCLUDES += $(OMNI_USD_INCLUDE_DIRS) $(PYTHON_INCLUDE_DIR)
LIBS += $(USD_LIBS) $(OMNI_LIBS) $(PYTHON_LIB)
LDFLAGS += $(OMNI_USD_LIB_DIRS) $(PYTHON_LIB_DIR)

OBJS = $(TARGETDIR)/$(PROGRAMNAME).o

# Build Targets

all: $(TARGETDIR)/$(PROGRAMNAME)

# $@ matches the target; $< matches the first dependent
$(TARGETDIR)/$(PROGRAMNAME): $(OBJS)
	echo Linking $(PROGRAMNAME)
	g++ -o $@ $< $(LDFLAGS) $(LIBS)

$(OBJS): $(PROGRAMNAME).cpp | $(TARGETDIR)
	g++ $(INCLUDES) $(CXXFLAGS) -c $< -o $@

$(TARGETDIR):
	@echo Creating $(TARGETDIR)
	@mkdir -p $(TARGETDIR)

clean:
	rm -rf $(TARGETDIR)

Windows

Create a new Visual Studio 2019 or 2022 project based on the C++ Console App, Empty Project template and call it UsdTraverse. Make sure that the solution and project files live in $project_root. Add the CPP source that traverses the USD file to the project. All of the settings specified in this section are found by right clicking on the created project and selecting Properties from within Visual Studio.

Header Include Paths

VC++ Directories > External Include Directories

connect-sdk/target-deps/carb_sdk_plugins/include
connect-sdk/target-deps/omni_connect_sdk/$(CONFIGURATION)/include
connect-sdk/target-deps/python/include
connect-sdk/target-deps/usd/$(CONFIGURATION)/include
connect-sdk/target-deps/usd/$(CONFIGURATION)/include/boost-1_78
Library Include Paths

VC++ Directories > Library Directories

connect-sdk/target-deps/carb_sdk_plugins/_build/windows-x86_64/$(CONFIGURATION)
connect-sdk/target-deps/omni_connect_sdk/$(CONFIGURATION)/lib
connect-sdk/target-deps/python/libs
connect-sdk/target-deps/usd/$(CONFIGURATION)/lib
Compiler Flags from Settings
  • Windows requires the /std:c++17 flag, this can be enabled by setting the C/C++ > Language > C++ Language Standard to ISO C++17 Standard.

  • The OpenUSD C++ headers generate many compiler warnings, the /external:W0 flag will quiet them. Set C/C++ > External Includes > External Header Warning Level to Turn Off All Warnings (if the include folders were put into the External Include Directories list).

Preprocessor Definitions

C/C++ > Preprocessor > Preprocessor Definitions (all configurations)

BOOST_LIB_TOOLSET="vc142"
NOMINMAX
TBB_SUPPRESS_DEPRECATED_MESSAGES

Note: the debug configuration will need to specify to use debug TBB

TBB_USE_DEBUG=1
Libraries

Linker > Input > Additional Dependencies (All configurations)

omni_connect_core.lib
carb.lib
usd_arch.lib
usd_gf.lib
usd_kind.lib
usd_pcp.lib
usd_plug.lib
usd_sdf.lib
usd_tf.lib
usd_usd.lib
usd_usdGeom.lib
usd_usdLux.lib
usd_usdUtils.lib
usd_vt.lib
usd_ar.lib

For the release configuration

boost_python310-vc142-mt-x64-1_78.lib

For the debug configuration

boost_python310-vc142-mt-gd-x64-1_78.lib

Each OpenUSD module must be linked by the application separately. The list above is a subset of all of them, but actually more than what the example requires. For instance, usd_usdLux.lib includes the UsdLux : USD Lighting Schema, but the example doesn’t actually use any of the UsdLux interface. The developer can trim this library list according to the needs of their application.

Runtime Environment

As stated earlier, the $CARB_APP_PATH environment variable must be set for an app to properly function with the Connect SDK. Also, the application must be able to find the shared libraries located in $CARB_APP_PATH/lib. These variables should be setup from a launching script, Visual Studio debugger settings, or from within the application itself before initializing the Connect Core module.

run_connect_app.sh

#!/bin/bash

set -e

export CARB_APP_PATH=./connect-sdk/linux-x86_64/release
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${CARB_APP_PATH}/lib

./release/UsdTraverse "$@"

run_connect_app.bat

set CARB_APP_PATH=connect-sdk/windows-x86_64/release
set PATH=%PATH%;%CARB_APP_PATH%/lib
x64\release\UsdTraverse.exe %*

Test a Connector

It is a good idea to author test data in your source format which you can use during development and for regression testing.

Once your data is converted to USD, it is recommended to test it for correctness & compliance with OpenUSD and Omniverse expectations, using the Omniverse Asset Validator. It is a Python module which you can use to run a suite of tests that check for common USD authoring mistakes.

Note

The Asset Validator documentation presents as a Kit Extension, but Kit is not required to use it. You can see example uses in Connect Samples.

Debug a Connector

Debugging via Logs

If you are hitting issues integrating Connect SDK into your Connector, the first thing to check is the runtime logs. Edit your omni.connect.client.toml to enable higher stdout log levels (i.e. set /log/outputStreamLevel to Warning or Info). See Log Configuration for more details.

Make sure to increase verbosity in all channels if you have limited some of them previously. Similarly, you may want to increase file log levels in all channels (i.e. set /log/fileLogLevel to Info or even Verbose). Then re-install your client config, re-run your application, and read through the logs to see if any messages give you insight into the problem.

Note

Verbose logging is very noisy. If you use this level you will likely want to use file logging, and you may want to lower the carb channel specifically via /log/channels/carb = “Info”

A common set of logging settings used for verbose debugging is:

[log]

# make all streams provide as much detail as possible
level = "Verbose"
outputStreamLevel = "Verbose"
fileLogLevel = "Verbose"

# unmask any specifically overridden channels
channels."*" = "Verbose"

# lower carb and omni.client unless also debugging those underlying subsystems
channels.carb = "Info"
channels."omni.client" = "Info"

USD Debug Logging

OpenUSD ships with a debug logging feature that prints to stdout (this is separate to the Omniverse logging described above). You can configure OpenUSD logging using the TF_DEBUG environment variable or the TfDebug interface. All of the debug message types are available using the TfDebug::GetDebugSymbolDescriptions() method.

Here are some useful examples that are present in recent USD releases:

AR_RESOLVER_INIT         : Print debug output during asset resolver initialization
PLUG_LOAD                : Plugin loading
PLUG_REGISTRATION        : Plugin registration
USD_CHANGES              : USD change processing
USD_STAGE_LIFETIMES      : USD stage ctor/dtor messages

Combine multiple symbols and wildcards to enable multiple symbol messages:

TF_DEBUG=*               : Enable all debug symbols
TF_DEBUG=PLUG_* AR_*     : Enable debug symbols for all ``PLUG_*`` and ``AR_*`` messages

Tip

Misconfiguring the ArResolvers is a common issue when starting new Connectors, and often presents itself as mysterious failures to open SdfLayers or create UsdStages. If either of those are occurring, use TF_DEBUG=’PLUG_* AR_*’ to debug if your resolvers are correctly configured & loading as expected.

Attaching a Debugger

If you wish to attach a debugger to a process that’s initializing the Connect SDK Core module, set /app/waitForDebugger = true. This will pause the process in omni::connect::core::startup() immediately after the settings are loaded. You can skip the pause and debugger connection by hitting any key in the console (stdin). Note that the process ID is printed to the console (stdout). Once a debugger is attached the process will continue to run, so a breakpoint should be set before attaching if the intention is to have the process break immediately for debugging.

Debugging Crashes

If you are experiencing segmentation faults or other hard crashes, try attaching a debugger. In many circumstances, it should be possible to start debugging a Connector from a release build. The Carbonite Crash Reporter is configured, and it provides a convenience mechanism to pause for a debugger when crashes are encountered. Set /crashreporter/debuggerAttachTimeoutMs to 30000 and wait for the Process ID to be output, then attach your debugger of choice.

You may also wish to set /crashreporter/preserveDump to true if you intend to inspect the .dmp file manually. See Carbonite’s Loading a Crash Dump to Investigate for more information on using the dmp files. The dump files will be located in the $data subdirectory relevant to your current application. See Persistent Data for details.

You can of course also re-compile against the debug package of the Connect SDK along with any common dependencies if you need to. Note however that in addition to the standard differences between release & debug (e.g. optimization and asserts), some runtime behaviors change in debug builds, especially within the Carbonite framework & its plugins.

If all else fails, do please reach out to the Connect SDK team in the appropriate support forums.