Create a Native Application#
The next step to familiarize yourself with the OpenUSD Exchange SDK is to create a simple standalone application.
Note
This section specifically does not use Python wheels. It instead installs the SDK dependencies within a project structure of a native application, which may or may not include python runtime.
This section will teach you how to create an application that opens a UsdStage, reports basic stage configuration details, and lists all of the UsdPrim paths.
This walkthrough will use these tokens:
$project_root- the base directory where the project application is locatedTo keep things clean, it is recommended that this is completely separate from either the OpenUSD Exchange SDK or Exchange Samples repo folders
$config- the build configuration (debugorrelease)$platform- the platform (linux-x86_64,linux-aarch64, orwindows-x86_64)
Install the SDK#
Assembling the minimal requirements for the OpenUSD Exchange SDK can be complicated, so there is an install_usdex 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.
Running these commands from either the Samples root folder, or the usd-exchange repository itself, will generate the _install folder for both debug and release configurations and deep copy them to your project root.
The copy flags matter, as the target-deps folders contain packman links (soft links on Linux, junctions on Windows) and a link-preserving copy produces a project that breaks as soon as it moves to another machine. On Linux, -L dereferences those links and -T prevents _install from nesting itself under an existing usdex folder. On Windows, /E copies all subdirectories including empty ones, and robocopy follows links and junctions unless /SL or /SJ is specified.
# from usd-exchange-samples, fetch the SDK package (which provides install_usdex) without compiling the samples ./build.sh --generate ./repo.sh install_usdex --config release --install-python-libs ./repo.sh install_usdex --config debug --install-python-libs cp -LrT _install "$project_root/usdex"
@rem from usd-exchange-samples, fetch the SDK package (which provides install_usdex) without compiling the samples .\build.bat --generate .\repo.bat install_usdex --config release --install-python-libs .\repo.bat install_usdex --config debug --install-python-libs robocopy /E "_install" "$project_root\usdex" > NUL
Note
Run install_usdex from either the Exchange Samples or the Exchange SDK root directory. From the SDK repository, it works on a fresh clone. The Samples repository consumes the tool from the SDK package and does not ship it. Therefore, build.sh|bat --generate must download the package before repo.bat|sh install_usdex is available. In the SDK repository, the default SDK version matches its CHANGELOG.md. In the Samples repository, the default SDK version matches the package pinned in deps/usd-exchange-deps.packman.xml. Use --version to override either default.
Caution
Each install_usdex call updates its staging and install directories. Use separate directories or repository clones for different OpenUSD versions. Otherwise, the new runtime conflicts with applications built against the previous runtime.
This tree describes the proposed file layout for the project:
$project_root
│ Makefile or UsdTraverse.sln|vsproj
│ UsdTraverse.cpp
│ ...
└───usdex
├───target-deps <----- build dependencies
│ ├───materialx
│ ├───python
│ ├───tbb
│ ├───usd
│ └───usd-exchange
└───$platform/$config <----- runtime dependencies
├───lib
└───python
├───pxr
└───usdex
This _install folder will be copied into $project_root/usdex 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 install_usdex documentation.
Runtime Dependencies#
The install_usdex 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 OpenUSD Exchange SDK, see the detailed runtime requirements.
Sample Program#
The application performs a few simple things with OpenUSD and the OpenUSD Exchange SDK:
Expects one argument, the path to a USD stage
Acceptable forms:
C:/USD/helloworld.usdor/tmp/USD/helloworld.usd- an absolute pathA relative path based on the CWD of the program (
sample.usda)
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
xformablethen print its position
It is included here to copy into a UsdTraverse.cpp file within $project_root
// SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: MIT
//
#include <usdex/core/Core.h>
#include <usdex/core/XformAlgo.h>
#include <pxr/pxr.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 <iomanip>
#include <iostream>
// The program expects one argument, a path to a USD file
int main(int argc, char* argv[])
{
// Print USD and Python versions
std::cout << "USD Version: " << PXR_MAJOR_VERSION << "." << PXR_MINOR_VERSION << "." << std::setfill('0') << std::setw(2) << PXR_PATCH_VERSION
<< std::endl;
std::cout << "USD Exchange Version: " << usdex::core::version() << std::endl;
std::cout << "Python Version: " << PY_VERSION << std::endl;
if (argc != 2)
{
std::cout << "Please provide a local file path to a USD stage to read." << std::endl;
return -1;
}
std::cout << "OpenUSD Stage Traversal: " << argv[1] << std::endl;
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: " << pxr::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 = usdex::core::getLocalTransform(prim);
std::cout << ":" << xform.GetTranslation();
}
std::cout << std::endl;
}
}
Build Configuration#
The build configurations below apply to the default flavor of OpenUSD Exchange SDK. Certain settings will vary for different flavors (e.g. python version).
Linux#
For Linux, all of the build configuration settings are described in the Makefile included here:
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: MIT
# This makefile is a simple example for an application, or converter for including, linking, and executing with
# OpenUSD and the OpenUSD Exchange 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 OpenUSD, the OpenUSD Exchange SDK, and other dependencies are present in the `$project_root/usdex/target-deps` directory
DEPSDIR = $(CURDIR)/usdex/target-deps
PYTHONVER = python3.12
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=1 -std=c++17
endif
# Ignored Warnings
ifndef IGNORED_WARNINGS
IGNORED_WARNINGS = -Wno-deprecated -DTBB_SUPPRESS_DEPRECATED_MESSAGES
endif
# Include search directories
USDEX_INCLUDE_DIRS = \
-isystem $(DEPSDIR)/usd-exchange/$(CONFIG)/include \
-isystem $(DEPSDIR)/usd/$(CONFIG)/include \
-isystem $(DEPSDIR)/tbb/$(CONFIG)/include
# USD libs (most of these not required, but this is a proper set for a fully featured converter)
USD_LIBS = \
-lusd_ar \
-lusd_arch \
-lusd_gf \
-lusd_js \
-lusd_kind \
-lusd_pcp \
-lusd_plug \
-lusd_python \
-lusd_sdf \
-lusd_tf \
-lusd_trace \
-lusd_ts \
-lusd_usd \
-lusd_usdGeom \
-lusd_usdLux \
-lusd_usdMtlx \
-lusd_usdPhysics \
-lusd_usdShade \
-lusd_usdUI \
-lusd_usdUtils \
-lusd_vt \
-lusd_work
# OpenUSD's shared libs pull in oneTBB; link it explicitly (the name differs by config) so the executable resolves the transitive TBB symbols they reference
ifeq ($(CONFIG),debug)
USD_LIBS += -ltbb_debug
else
USD_LIBS += -ltbb
endif
USDEX_LIBS = \
-lusdex_core
# Library dependency directories
USDEX_LIB_DIRS = \
-L$(DEPSDIR)/usd-exchange/$(CONFIG)/lib \
-L$(DEPSDIR)/usd/$(CONFIG)/lib \
-L$(DEPSDIR)/tbb/$(CONFIG)/lib
# usdMtlx depends on MaterialX, which lives in a separate dependency directory
MATERIALX_LIB_DIR = $(DEPSDIR)/materialx/$(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)
INCLUDES += $(USDEX_INCLUDE_DIRS) $(PYTHON_INCLUDE_DIR)
LIBS += $(USD_LIBS) $(USDEX_LIBS) $(PYTHON_LIB)
LDFLAGS += $(USDEX_LIB_DIRS) $(PYTHON_LIB_DIR) -Wl,-rpath-link,$(MATERIALX_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)
Build both configurations from $project_root:
make
make CONFIG=debug
Windows#
Create a new Visual Studio 2022 (or newer) 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.
Note
The OpenUSD Exchange Samples include Visual Studio solution and project files with all of the below build configuration settings setup. Because Visual Studio solutions aren’t as portable as Makefiles, your mileage may vary with them and you may need to start from scratch with a new solution.
Header Include Paths#
VC++ Directories > External Include Directories
usdex/target-deps/usd-exchange/$(CONFIGURATION)/include
usdex/target-deps/python/include
usdex/target-deps/usd/$(CONFIGURATION)/include
usdex/target-deps/tbb/$(CONFIGURATION)/include
Library Include Paths#
VC++ Directories > Library Directories
usdex/target-deps/usd-exchange/$(CONFIGURATION)/lib
usdex/target-deps/python/libs
usdex/target-deps/usd/$(CONFIGURATION)/lib
Compiler Flags from Settings#
Windows requires the
/std:c++17flag, this can be enabled by setting theC/C++ > Language > C++ Language StandardtoISO C++17 Standard.The OpenUSD C++ headers generate many compiler warnings, the
/external:W0flag will quiet them. SetC/C++ > External Includes > External Header Warning LeveltoTurn Off All Warnings(if the include folders were put into theExternal Include Directorieslist).
Preprocessor Definitions#
C/C++ > Preprocessor > Preprocessor Definitions (all configurations)
NOMINMAX
TBB_SUPPRESS_DEPRECATED_MESSAGES
The debug configuration will also need to use explicitly enable the debug build of TBB:
TBB_USE_DEBUG=1
Libraries#
Linker > Input > Additional Dependencies (All configurations)
usdex_core.lib
usd_ar.lib
usd_arch.lib
usd_gf.lib
usd_kind.lib
usd_pcp.lib
usd_plug.lib
usd_python.lib
usd_sdf.lib
usd_tf.lib
usd_ts.lib
usd_usd.lib
usd_usdGeom.lib
usd_usdLux.lib
usd_usdPhysics.lib
usd_usdShade.lib
usd_usdUI.lib
usd_usdUtils.lib
usd_vt.lib
usd_work.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.
Debugger Environment#
If you want to launch or debug the sample from within Visual Studio, the PATH environment variable must be set in the settings:
Configuration Properties > Debugging (All configurations)
PATH=usdex/windows-x86_64/$(CONFIGURATION)/bin
Runtime Environment#
The application must be able to find the shared libraries, located in usdex/$platform/$config/lib on Linux and usdex/$platform/$config/bin on Windows. These variables should be setup from a launching script, Visual Studio debugger settings, or from within the application itself before using the OpenUSD Exchange Core module.
run_usdex_app.sh#!/bin/bash set -e export CONFIG="${CONFIG:-release}" export PLATFORM="linux-$(uname -m)" export RUNTIME_PATH=./usdex/${PLATFORM}/${CONFIG} export LD_LIBRARY_PATH=${RUNTIME_PATH}/lib:${LD_LIBRARY_PATH} ./${CONFIG}/UsdTraverse "$@"
run_usdex_app.bat@echo off setlocal if not defined CONFIG set CONFIG=release set RUNTIME_PATH=usdex/windows-x86_64/%CONFIG% set PATH=%RUNTIME_PATH%/bin;%PATH% x64\%CONFIG%\UsdTraverse.exe %*
Warning
If OpenUSD is installed on your system and its paths are in your PATH environment variable, the samples may not run correctly.
Debugging#
For more information on debugging you application, see Testing and Debugging.