Awesome
Introduction
This repository contains a set of samples that illustrate authoring of different kinds of plug-ins for USD. In particular, this repository contains plug-in samples for:
- USD schemas (both codeful and codeless)
- File Format Plugins
- Dynamic Payloads
- Hydra 2 Scene Indices
Additionally, this repository contains a set of tools that can be used to generate schema code and templates that can be used for both cmake
and premake
to build the plug-ins using compiler / linker settings consistent with those used when building USD libraries. The sections below introduce these samples with the hope of helping you get started on your USD plug-in journey. Feel free to fork this repository, delete the portions you don't need, and customize the remaining in whatever way suits your USD environment.
While the repository is set up in such a way that you can quickly get started using stock Pixar builds (in this case, 23.05
), the intent is to enable you to "bring your own" USD builds by specifying where it resides in configuration for the included tooling. Note that not all features included in these samples are available in all USD versions, so some samples may not build out of the box against certain USD versions without modifications. In general, the schema examples should be compatible with anything 21.02
and later, the dynamic payload example with anything 22.11
and later, and the hydra 2 examples with anything 23.05
and later.
Quick Start
Prerequisite: You must have CMake 3.20+ installed on your system and available through the PATH
If you want to directly build and try out the samples in usdview
, you can use the provided tools to build the libraries and configure the environment to enable you to load the sample scenes in usdview
. The commands below assume either a Linux environment or git-bash
on Windows.
./build.bat # builds the release build of the samples into _install\windows-x86_64\release (Windows)
./build.sh # builds the release build of the samples into _install/linux-x86_64/release (Linux X86)
# or into _install/linux-aarch64/release (Linux ARM)
source setenvwindows # sets up a python virtual environment (_venv), installs PySide and PyOpenGL, and sets the PATH / PYTHONPATH
# to the built sample libraries and the USD 23.05 distribution, sets the PXR_PLUGINPATH_NAME to include
# paths to the sample plugInfo.json files (Windows)
source setenvlinux # sets up a python virtual environment (_venv), installs PySide and PyOpenGL, and sets the LD_LIBRARY_PATH / PYTHONPATH
# to the built sample libraries and the USD 23.05 distribution, sets the PXR_PLUGINPATH_NAME to include
# paths to the sample plugInfo.json files (Linux)
usdview resources/scene.usda --unloaded # opens usdview on the provided sample scene with a dynamic payload in an unloaded state
Different samples rely on different sample scenes:
Dymamic Payloads
Open usdview
with the resources/scene.usda
sample stage. Once usdview
has been opened, you can load the dynamic payload by right-clicking on MetropolitanMuseumOfArt
and selecting Load
. Using the default metadata configuration, this will load the payload as a set of deferred reads invoking REST APIs to retrieve department and object data for the Metropolitan Museum of Art. Alternatively, you can open usdview
fully loaded without the --unloaded
option. Note that this sample does not render anything - it is there to illustrate the dynamic scene structure created from the information received via the REST API.
Hydra 2 Geospatial Coordinates
Open usdview
with the resources/wgs84/deutschebahn-rails.usda
sample stage. In this example, source WGS84 coordinates a resolved in Hydra 2 and a reference map displayed in the background to ensure correct resolution.
We thank Digitale Schiene Deutschland for the collaboration and for providing exemplary railway map data.
Hydra 2 Metrics Assembler
Open usdview
with the resources/metrics_assembler.usda
sample stage. You can play with the value of metersPerUnit
in the metrics_assembler_2.usda
layer to observe what happens when this value is different from that of the metersPerUnit
value of the root stage.
Hydra 2 Warp
Several examples are provided to illustrate the use of NVIDIA's warp in conjunction with scene indices:
warp_demo_mesh.usda
- Sample for using warp to deform a meshwarp_demo_sim.usda
- Sample demonstrating the use of warp to simulate physics against a set of sphere particles
Licensing Notes
The content herein is subject to the license here. The dynamic payload example makes use of the Metropolitan Museum of Art Collection API, and usage of this is subject to terms and conditions specified here. In particular, because the API does not require registration or use of an API key, request rates should be limited to 80 requests per second.
General Project Structure
The repository is structured as follows:
deps
src
hydra-plugins
omniGeoSceneIndex
omniMetricsAssembler
omniWarpSceneIndex
kit-extension
usd-plugins
dynamicPayload
fileFormat
schema
tools
bootstrap.py
build.bat
build.sh
repo.toml
setenvwindows
setenvlinux
setenvwindows.bat
All example source code is kept in the src
diretory, with each sub folder demonstrating a different type of USD plug-in. The remaining files are there to support the schema generation and build infrastructure necessary to create the plug-in libraries. This infrastructure uses an NVIDIA tool called packman
to pull packages required for schema and makefile generation. These include the following:
- Stock OpenUSD 23.05 builds
- A python distribution used to build the above USD packages (Python 3.10)
- A tool (
repo_usd
) used to generate schema code and makefiles in the desired format (cmake
/premake
) - The jinja python package (3.1.2) and its dependencies to support
usdGenSchema
(installed to a local folder viarepo_usd
) - The installation of PyOpenGL, PySide, and warp-lang to a virtual environment to support running the provided examples easily
By convention, all folders starting with _
are derived artifacts and can be safely deleted when cleaning the repository. In particular, four of these folders are used:
- _repo (stores the download
repo_usd
package for use) - _build (default location for generated and intermediary build artifacts)
- _install (default location for built and staged plug-ins)
- _venv (a virtual environment created to setup the environment for trying the samples out in
usdview
)
These folders are used or not depending on various configuration options you provide to the repo_usd
tool via the repo.toml
file. Options that can be provided, as well as command line options that can be passed to the build.bat
/ build.sh
scripts are described in the section Tool Options
below.
Each set of samples is accompanied by a README
containing additional information about the relevant part of USD being explored and how the sample is constructed. These can be found here:
The remainder of this document explores the USD plugin system in general and the tooling provided to build the samples in greater depth.
USD Plugins
USD provides many different extensibility points to allow additional data to be represented, loaded, and worked with as prims and attributes within the USD runtime. These extensiblity points are implemented via plugins, which provide definition of additional data (schemas) and certain runtime behaviors (data loading and asset resolution). Plugins are implemented via libraries that contain classes that implement base APIs provided by USD to interact with the USD runtime and declared to USD via information contained in a plugInfo.json
file.
In general, the plugin system of USD works in the same way regardless of plugin type. USD needs a few things for the plugin system to work:
- An abstract base class declaring the API for the plugin type that is registered with the type system
- A factory function for creating new instances
- A mechanism for loading the plugin into the system
For example, in the case of implementing a custom file format extension, USD provides:
- An abstract base class via
SdfFileFormat
- A factory object reponsible for creating instances of the plugin type via
Sdf_FileFormatFactory
- An object that reads information of plugins that implement
SdfFileFormat
and loads them into the runtime viaSdf_FileFormatRegistry
This can be illustrated in the diagram below:
To implement a plugin, a developer needs to do a few things:
- Create a class that implements the API of the abstract base class
- Register the type with
Tf
- Declare the plugin and the information contained therein in a
plugInfo.json
file - Register the plug-in with the system (either implicitly by specifying a path to the
plugInfo.json
file inPXR_PLUGINPATH_NAME
or explicitly via aRegisterPlugins
call in controlling code)
From the point of view of the USD runtime, plugins are read generically by interpreting the plugInfo.json
file and deriving information about the plugin that can be used to load the plugin into the runtime when requested. This is the responsibility of the plug
USD library. The metadata of all plugins (regardless of type) is held in the PlugRegistry
object. On USD runtime startup, the information in all plugInfo.json
files accessible from paths declared in PXR_PLUGINPATH_NAME
are loaded, interpreted, and stored in the PlugRegistry
singleton instance. Additionally, any plugInfo.json
files that are found via a RegisterPlugins
call on the singleton are loaded, interpreted, and stored (more on this later, because order of operations are important!). The metadata of each plugin is represented by a PlugPlugin
instance.
Objects that are interested in plugins of a certain type may query the PlugRegistry
for all plugins that derive from a type registered in the type system via a call to GetAllDerivedTypes
. This returns all registered types that derive from the requested type; from this the object can get the actual plugin metadata via a call to GetPluginForType
. Finally, the object can load the plugin from the metadata via Load
in order to work with the specific API implemented by the plugin. This loads the library associated with the plugin into memory and makes the types in it accessible to the system. In general, the objects that manage this information are specific for a particular plugin type (e.g. SdfFileFormat
) and are typically singletons in the USD runtime (e.g., Sdf_FileFormatRegistry
).
The file format objects that implement the USD plugin architecture for SdfFileFormat
are given below:
In all cases, the singleton objects that load plugins do so once at the time of first access and cache that information. This means that any code that performs a call to RegisterPlugins
must be executed prior to the first call to the singleton object managing plugins of that type!.
For illustrative purposes, the edf
file format plugin contained within this sample also has an example of a type that manages plugins (of type IEdfDataProvider
) in a similar way that the built-in USD managers manage their own plugin types.
Using the Tool to Generate Schema Code and Build Files
These samples use a tool called repo_usd
to generate the schema code and plug-in information that will be built and distributed. This is a small wrapper around usdGenSchema
, provided with a USD build, with several options that control where the information is generated and optionally if build files (e.g., cmake or premake files) should be generated to support build of the schema libraries. All options are defined in a toml
file called repo.toml
at the root of the repository.
A toml
file is just a set key / value pairs. Related settings are grouped by heading keys defined in the []
pair and individual options are defined using x=y
notation. Underneath, these turn into dictionaries that are processed by the repo_usd
tool to interpret the options into a set of generation instructions that process your USD plugins to generate source code and build files. These options include:
- General configuration options that apply across all plugins
- Configuration options specific to an individual plugin of all types (including schema types)
- Configuration options specific to an individual schema type plugin
General Setup
Different organizations may be working with different versions of USD at any given time. Plugins, however, must be built separately for each individual USD distribution that you want to work with. As such, first we must tell repo_usd
where the USD dependencies are so that it knows where to find the include / lib files required for build file generation, and well as where to find usdGenSchema
for generating code from schema definition files. repo_usd
needs two locations to function properly:
- The path to the USD build that will be used (referred to as
usd_root
) - The path to a Python environment consistent with that which built the referenced USD libraries (referred to as
usd_python_root
)
For example, when building against NVIDIA's USD libraries pulled by packman
, the repo.toml
file might be configured as follows:
[repo_usd]
usd_root = "${root}/_build/usd-deps/nv-usd/%{config}"
usd_python_root = "${root}/_build/usd-deps/python"
A couple of things to note here:
${root}
is a special token thatrepo_usd
will replace with the path to the root of the repository. Several paths declared inrepo.toml
must be declared relative to${root}
. These include:- The path to the USD installation (
usd_root
) - The path to the Python installation (
usd_python_root
) - The path to a schema file for a schema plugin (
schema_file
) - The path to the root of a plugin (
plugin_dir
) - The path to the directory to generate code / build files into for a plugin (
generate_dir
) - The path to the root directory on which the built artifacts will be deployed for a plugin (
install_root
)
- The path to the USD installation (
- The paths here reference the
linkPath
property that is defined in thepackman
deps file you have configured to pull the appropriate USD and python packages. Whenpackman
pulls these packages down, it will place them in these locations. - To change the USD build you are referencing, simply change the path specified here (relative to
${root}
). Make sure that the python environment you use is consistent with that which was used to build the USD libraries being referenced (e.g. if you built USD with Python 3.10, make sure yourusd_python_root
points to an environment containing Python 3.10).
The use of packman
has been enabled in this repository to pull the relevant USD and python packages (22.11 and 3.10 respectively) for a turnkey type solution that builds plugins compatible with NVIDIA Omniverse (105+). If you want to use a different version of USD simply change the paths that are specified in usd_root
and usd_python_root
.
By default, repo_usd
will attempt to detect the USD library prefix for your build dynamically. This works in most situations, but if it is unable to detect it, you may specify the prefix explicitly in configuration via the usd_lib_prefix
attribute. For example, if your USD libraries were of the form lib_arch, lib_tf, etc., you would specify the prefix as follows:
[repo_usd]
usd_root = "${root}/_build/usd-deps/nv-usd/%{config}"
usd_python_root = "${root}/_build/usd-deps/python"
usd_lib_prefix = "lib_"
repo_usd
can also generate build files in either cmake
or premake
format (cmake
is the default). If you would like to take advantage of this functionality, there are a few more options in the repo.toml
file that are required:
- The build file format you would like to generate (the default is
cmake
and need not be specified unless you want to change it) - Whether or not you would like to generate the root build files. By default, this option is
false
(see below for further explanation)
These options can be set in the repo.toml
file as follows:
[repo_usd]
usd_root = "${root}/_build/usd-deps/nv-usd/%{config}"
usd_python_root = "${root}/_build/usd-deps/python"
generate_plugin_buildfiles = true
To use premake
, add the plugin_buildfile_format
option:
[repo_usd]
usd_root = "${root}/_build/usd-deps/nv-usd/%{config}"
usd_python_root = "${root}/_build/usd-deps/python"
generate_plugin_buildfiles = true
plugin_buildfile_format = "premake"
When the generate_plugin_buildfiles
option is on, a build file in the specified format will be generated for each configured plugin to the following locations:
- the configured
generate_dir
for the plugin (orplugin_dir
if no separategenerate_dir
is specified)
The remainder of this section assumes that the build file format will be the default (cmake
). When additional options are required for premake
this will be noted specifically.
A Note on Tokens in repo.toml
Paths declared in repo.toml
may include tokens - strings that will be replaced based on the current value of something in the build process. In most cases, you will want to take advantage of tokens that represent the platform
the build is occurring on and the config
being built. The presence of these tokens is a generic way to specify cross-platform / cross-configuration paths that can be evaluated either at repo_usd
load time or at build time. repo_usd
supports two types of token strings:
- Tokens that are prefixed with the
$
character (e.g.,${platform}
,${config}
) - Tokens that are prefixed with the
%
character (e.g.,%{platform}
,%{config}
)
The first type of tokens are evaluated when the repo.toml
configuration is loaded by repo.usd
. The second type of tokens are used to inform repo_usd
to emit paths that are generic for the target build system. For example, %{config}
will be replaced by %{cfg.buildcfg}
for premake
and PXR_PLUGIN_CONFIGURATION
for cmake
. These tokens are then evaluated by the build system at build time depending on your build configuration. Using tokens generically allows a single premake5.lua
or CMakeLists.txt
file to be emitted that can be used on multiple platforms with multiple configurations (i.e., this allows you to generate these files once and commit them to your source control system, if desired).
In addition, the special token ${root}
is used to generically designate the root directory of the repository. The use of the above tokens (%
/ $
) are restricted to paths that are based on ${root}
. That is, paths like include_dir
, which are specified relative to install_root
, do not support the use of these tokens.
Specifying Plugin Specific Options
Each USD plugin in the repository can be configured with a number of options. All plugins are configured in the repo.toml
file in the form repo_usd.plugin.x
where x
defines the name of the plugin (and from which the compiled library name will derive). All plugins must specify a path in the plugin_dir
option, which informs the tool what the plugin's source code root directory will be from which all source files will be referenced. For example, assume we had a plugin named myFileFormat
. We could configure it as follows:
[repo_usd]
usd_root = "${root}/_build/usd-deps/nv-usd/%{config}"
usd_python_root = "${root}/_build/usd-deps/python"
generate_plugin_buildfiles = true
[repo_usd.plugin.myFileFormat]
plugin_dir = "${root}/src/myFileFormat"
Each plugin must also define the USD libraries that it is dependent on. Specifying the USD library dependencies is required for all USD plugins, and each may depend upon a different set. It is also necessary when defining codeful schemas, whether you wish to generate build files for the schema plugin or not (see below). These are the base names of the USD libraries (e.g. arch
, tf
, etc.). These are defined in the usd_lib_dependencies
option:
[repo_usd]
usd_root = "${root}/_build/usd-deps/nv-usd/%{config}"
usd_python_root = "${root}/_build/usd-deps/python"
generate_plugin_buildfiles = true
[repo_usd.plugin.myFileFormat]
plugin_dir = "${root}/src/myFileFormat"
usd_lib_dependencies = [
"arch",
"tf",
"vt",
"sdf",
"usd"
]
Plugins may specify a separate generate_dir
path (relative to ${root}
). If specified, this is the directory all generated files will be output to (including schema code and build files). If not specified, repo_usd
will use plugin_dir
as the directory.
repo_usd
exposes a number of options that allow you to control the target directory structure for your plugin. These include:
install_root
: path at which to root the plugin output files (default ="${root}/_install/${platform}/${plugin_name}
). This must be specified relative to${root}
include_dir
: path relative toinstall_root
where public headers for the plugin will be copiedlib_dir
: path relative toinstall_root
where the plugin C++ library will be built toresources_dir
: path relative toinstall_root
where resource files (such asplugInfo.json
,generatedSchema.usda
, etc.) will be copied
You can change any of these options per-plugin by specifying values for each of the above keys in the repo.toml
file section of the specific plugin. In particular, many choose to specify install_root
explicitly and leave the others as their defaults relative to this path.
When the option generate_plugin_buildfiles
is on, each plugin is required to specify the files that will be used to build the library the build file will be generated for. This requires at minimum the following options to be defined (all paths relative to generate_dir
, which defaults to plugin_dir
if not specified explicitly):
public_headers
: a list of paths that denote the header files that should be included in the generated project and which should also be copied to the specifiedinclude_dir
during the build step.private_headers
a list of paths that denote header files that should be included in the generated project but which should not be copied toinclude_dir
.cpp_files
: a list of paths that denote cpp files that should be included in the generated project that contribute source for the library that will be built.resource_files
: a list of paths that denote files that should be included as resources that will be copied to the specifiedresources_dir
during the build step. At minimum, this typically includes theplugInfo.json
file for your plugin.
If your plugin also requires a Python module to be built, an additional set of options must be provided (all paths relative to generate_dir
, which defaults to plugin_dir
if not specified explicitly):
module_dir
: Path relative toinstall_root
where the Python library will be built to and python module files copiedpymodule_cpp_files
: A list of C++ file paths that will be compiled into the Python module librarypymodule_files
: A list of python files to include in the Python module distribution. These files will be copied to the targetmodule_dir
with relative paths retained.
Note that in the case of schemas (see below), the generated files will be automatically added to the appropriate list above to be included in the respective C++ or Python libraries.
When using premake
, you may also specify the directory to which the output of the premake
files are generated.
build_dir
: path relative to the repository root where you would like the projects created by premake to be generated. The premake file itself (premake5.lua
) is generated to the same directory as the source (generate_dir
orplugin_dir
ifgenerate_dir
is not explicitly specified), but the artifacts of the premake file will be generated to this location. By default, this location is${root}/_build/${schema_name}
. Note that this option is only valid forpremake
- CMake artifacts are generated in the directory specified when running CMake configure and mirrors the source tree.
Finally, additional configuration options are provided for you to specify include and library directories that are additional to the built-in USD and python ones derived from your usd_root
and usd_python_root
settings. As part of this, additional libraries may be specified that the target build will be linked to. Custom preprocessor definitions (in addition to those already added for USD plugin libraries) can also be added to each plugin. These are specified via the following options:
additional_include_dirs
: A list of additional directories that should be used to find include files the plugin may depend onadditional_library_dirs
: A list of additional directories that should be used to find library files the plugin may depend onadditional_libs
: A list of additional libs that need to be linked to the plugin to buildadditional_static_libs
: A list of additional libs that need to be statically linked to the plugin to buildpreprocessor_defines
: A list of preprocessor definitions to add to the project buildfile
All paths above should be specified relative to the generate_dir
of the plugin (or plugin_dir
if generate_dir
is not specified).
Finally, you can customize dependencies among plug-ins by using the depends_on
option:
depends_on
: A list of strings, each which refers to the name of a plugin that must be built prior to the one this option is attached to. The string used here is the same string you use in your definition of the root key (i.e., thex
in[repo_usd.plugin.x]
)
The above options are valid for all types of plugins. For plugins that also contain schema definitions, an additional set of options can be provided as discussed below.
Additional Options for Plugins that Contain Schemas
A schema definition file can be contained within a plugin, indicating that schema definitions and associated code (if not codeless) will be included in the resulting C++ and Python libraries. Codeful schemas require code to be generated via the usdGenSchema
tool that comes with the USD distribution and built into a library like any other USD plugin. Codeless schemas also require usdGenSchema
, but only resource files are generated (plugInfo.json
and generatedSchema.usda
). The content of the latter file is used by the UsdSchemaRegistry
to identify your schema types.
repo_usd
provides some additional options to configure code and build file generation of schema content in the [repo_usd.plugin.x]
section:
schema_file
: The path to theschema.usda
file defining the schema classes. This must be specified relative to${root}
.library_prefix
: The library prefix that is set in theschema.usda
file (necessary for generating the python wrapper code, only necessary for codeful schemas)is_codeless
: Whether or not the schema is codeless (by default, the schema is codeful, so this is only necessary if you have a codeless schema). If the schema is codeless, specifyingusd_lib_dependencies
is not required.
Note that the library_prefix
option here is different from the usd_lib_prefix
option defined above. While the latter defines the prefix on the base USD library name (if you are working with a distribution that has a prefix), the former refers to the value of the libraryPrefix
field of your schema.usda
file. You must ensure that the value of library_prefix
in the repo.toml
file matches the value of libraryPrefix
in your schema.usda
file.
Also note that defining the usd_lib_dependencies
is required for codeful schemas, even if the generate_plugin_buildfiles
option is false
. This is because one of the files that is generated (moduleDeps.cpp
) requires this information to correctly declare the dependencies in code.
Since schema definitions can vary between USD versions (particularly v20.08 and v21.02+), ensure that your schema.usda
file has a definition that is consistent with that expected by the USD version you are using to generate the code and build files.
A sample configuration for a codeless schema using these options is given below.
[repo_usd]
usd_root = "${root}/_build/usd-deps/nv-usd/%{config}"
usd_python_root = "${root}/_build/usd-deps/python"
generate_plugin_buildfiles = true
[repo_usd.plugin.mySchema]
schema_file = "${root}/src/schema/mySchema/schema.usda"
generate_dir = "${root}/src/schema/mySchema/generated"
is_codeless = true
Typical configuration of a plugin will define install_root
, include_dir
, lib_dir
, resource_dir
, and module_dir
(in the case of schemas) rather than leaving them to the defaults. For example:
[repo_usd]
usd_root = "${root}/_build/usd-deps/nv-usd/%{config}"
usd_python_root = "${root}/_build/usd-deps/python"
generate_plugin_buildfiles = true
plugin_buildfile_format = "premake"
[repo_usd.schema.mySchema]
schema_file = "${root}/src/schema/mySchema/schema.usda"
generate_dir = "${root}/src/schema/mySchema/generated"
library_prefix = "MySchema"
install_root = "${root}/_install/%{platform}/%{config}/mySchema"
include_dir = "include/mySchema"
lib_dir = "bin"
resource_dir = "resources"
module_dir = "MySchema"
usd_lib_dependencies = [
"arch",
"tf",
"vt",
"sdf",
"usd"
]
Note that schema configurations only need to include public_headers
, cpp_files
, pymodule_cpp_files
, pymodule_files
, and resource_files
if there are files to be included that are in addition to those that usdGenSchema
generates.
usdGenSchema
will generate most of the code necessary for your schema plugin. repo_usd
generates three additional files that in most cases are boilerplate that allow the schema module to be properly loaded by USD:
module.cpp
: Defines theTF_WRAP
statements required to expose the C++ schema classes to Python viaboost::python
moduleDeps.cpp
: Defines the module loader code for the USDTf
library__init__.py
: Defines the entry point to the schema Python module and invokes the right loader sequence in the USDTf
module
In almost all cases this code is boilerplate and as such generation of these files is on by default. In some cases, you may need to customize the content of one or more of these files. repo_usd
allows you to optionally turn off automatic generation of each of these files through three additional options:
generate_module_cpp_file
: Boolean informingrepo_usd
whether or not to generate themodule.cpp
file for the schema plugin (default =true
)generate_module_deps_cpp_file
: Boolean informingrepo_usd
whether or not to generate themoduleDeps.cpp
file for the schema plugin (default =true
)generate_init_py_file
: Boolean informingrepo_usd
whether or not to generate the__init__.py
file for the schema plugin (default =true
)
If you set these options to false
, make sure you have the right content in those files such that USD will load your schema.
The options above are enough to generate schema code and (optionally) build files. Even if your schema is codeless, build files will be generated in order to configure the plugInfo.json
file and get the resources (plugInfo.json
and generatedSchema.usda
) in the right target directory. Once the code and build files have been generated, it is up to the user to build the files using their chosen build system (e.g., cmake
, premake
, repo_build
for NVIDIA-projects, etc.). After everything has been built, a second run of repo_usd
is required to get the plugInfo.json
file configured properly in the target directory. The next section describes this process.
Configuring the plugInfo.json File
USD plugins are loaded into the USD runtime via the plugInfo.json
file and a call to RegisterPlugins
somewhere in the responsible loading code. The plugInfo.json
file has three properties (in addition to other definitions) that help USD root the plugin and find the library containing its functionality:
LibraryPath
: the path relative to the root of the plugin where USD can find the native library containing the plugin's implementationResourcePath
: the path relative to the root of the plugin where USD can find the resources (including theplugInfo.json
file itself) associated with the pluginRoot
: The path that is the root path of the plugin (relative to theplugInfo.json
file) where the other two paths above are rooted from
When usdGenSchema
generates the code for a schema, it also generates the plugInfo.json
file, but this file contains three placeholder tokens that must be replaced with real values before your plugin can be distributed. The replacement of these placeholder tokens with the proper paths is done as part of the Configure step.
In all cases, this must be done as a separate step after the library has been built using your build tools. Thus, typical generation workflows that involve schemas work in three steps:
- Run
repo_usd
to generate schema code and build files associated with plugins and schemas - Run your build tools to build the plugin libraries
- Run
repo_usd
again with the--configure-pluginfo
option to properly configure theplugInfo.json
file
To perform this configuration, repo_usd
uses the values you provided (or the defaults if not provided) in the lib_dir
and resources_dir
paths defined in the repo.toml
file. This means that whatever structure you create at this time is represented in the plugInfo.json
file, and any subsequent modification of this directory structure will typically make the paths configured in the plugInfo.json
file incorrect. Thus, after you run the configure step, your target directory structure is what is used for the plugin configuration - if you use the plugin subsequently somewhere else (e.g. a kit extension), make sure the directory structure is copied to your extension directory without modification such that the information in the plugInfo.json
file is correct. Use the install_root
, lib_dir
, include_dir
, module_dir
, and resources_dir
options to configure the directory structure how you need it to be for your extension.
The snippet below shows how to run repo_usd
with the --configure-pluginfo
option.
call "%~dp0tools\packman\python.bat" bootstrap.py usd --configure-pluginfo (Windows)
tools/packman/python.sh bootstrap.py usd --configure-pluginfo (Linux)
Root Build Files
If the generate_root_buildfiles
option is on, repo_usd
will also generate a root CMakeLists.txt
/ premake5.lua
file at the root of the repository that integrates the individual ones generated for each plugin. This is provided as a convenience for getting started, but is often insufficient for integration into an existing build process. As such, you may choose to generate this file once, and then turn this generation off and customize the generated file to your liking. While this turnkey type setup can be useful, you may also choose to write the main build files yourself and integrate those generated for each plugin in a way that best suits your own build infrastructure. If you choose to do this, you must include certain macros provided by repo_usd
that set compiler and linker switches, take care of copying public headers and resource files, etc. Interested parties can examine these files in _repo/repo_usd/templates
. At a minimum, your root CMakeLists.txt
file must have the following content (for the two example plugins used above):
# repo_usd requires CMAKE 3.20 minmum, but yours may be higher
# cmake_minimum_required(VERSION 3.20)
# create a projet e.g.:
# project(usd-plugins)
# include the cmake file required for declaring a plugin
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} _repo/repo_usd/templates/cmake)
include(PxrPlugin)
# add each plugin subdirectory to the list
add_subdirectory(src/plugins/myFileFormat)
add_subdirectory(src/schema/mySchema/generated)
Similarly, for premake
, your root premake5.lua
file must have the following:
require("_repo/repo_usd/templates/premake/premake5-usdplugin")
-- declare a workspace or use your existing one e.g.:
-- workspace(usd-plugins)
-- make sure these definitions are in the context of a workspace
-- they do not declare their own
require("src/plugins/myFileFormat/premake5")
require("src/schema/mySchema/generated/premake5")
NOTE: If you have the option generate_root_buildfile
on please ensure that you do not have a CMakeLists.txt or premake5.lua file already at your repository root or setting this option will overwrite it!
The samples provided in this repository have this option turned off (the default) because a properly configured root build file already exists.
What if I Want to Place the Generated Files Under Source Control?
If your schema definitions do not change often, you may choose to not run repo_usd
with every build. In this case, repo_usd
is run once (both steps, generate and configure) and the files are generated. If you choose to place the files in the generate_dir
under source control, ensure that the plugInfo.json
you place in source control is the one that was configured after the configure step and not the one prior (otherwise it will have the placeholder information generated by usdGenSchema
). This likely means as part of your one-time run of repo_usd
you will also need a copy step to copy the configured plugInfo.json
file back into the generate_dir
location to overwrite the template with the correct values.
Reference: Valid keys for repo_usd
and the repo.toml
File
The following keys are available to configure repo_usd
.
[repo_usd]
:
usd_root
: (Required string) Specifies the path to the built USD installation on diskusd_python_root
: (Required string) Specifies the path to a Python installation on disk compatible with that used to build USDgenerate_plugin_buildfiles
: (Optional bool default=false) True to generateCMakeLists.txt
/premake5.lua
filesplugin_buildfile_format
: (Optional string default=cmake)cmake
to generateCMakeLists.txt
files,premake
forpremake5.lua
filesgenerate_root_buildfile
: (Optional bool default=false) True to generate aCMakeLists.txt
file at the root of the repository that includes the individual pluginCMakeLists.txt
files (orpremake5.lua
file ifplugin_buildfile_format
ispremake
)usd_lib_prefix
: (Optional string default="") A string denoting any prefix that needs to be added to the USD library dependencies based on your USD installation
[repo_usd.plugin.x]
:
plugin_dir
: (Required string) Path relative to${root}
where the source code of the plugin residesgenerate_dir
: (Optional string default=plugin_dir) Path relative to${root}
where the build files (for all plugins) and schema files (for schemas) will be generated toinstall_root
: (Optional string default="${root}/_install/${platform}/x") Path relative to${root}
where the built artifacts will be placed for the plugininclude_dir
: (Optional string default="include") Path relative toinstall_root
wherepublic_headers
will be placedlib_dir
: (Optional string default="lib") Path relative toinstall_root
where the built C++ library will be placedresources_dir
: (Optional string *default="resources") Path relative toinstall_root
where allresource_files
will be copied to and whereplugInfo.json
will be configured fromusd_lib_dependencies
: (Required list of strings, unless this configuration is for a codeless schema in which case it is not required) List of base USD library names (e.g.,arch
,tf
, etc.) on which the plugin dependspublic_headers
: (Optional list of strings default=[]) List of header files relative toplugin_dir
that will be copied to theinclude_dir
targetprivate_headers
: (Optional list of strings default=[]) List of header files relative toplugin_dir
that are required for compilation but that will not be copied to theinclude_dir
targetcpp_files
: (Optional list of strings default=[]) List of C++ files relative toplugin_dir
that are required for compilationresource_files
: (Optional list of strings default=[]) List of additional files relative toplugin_dir
that will be copied to theresources_dir
target (e.g.,plugInfo.json
)additional_include_dirs
: (Optional list of strings default=[]) List of additional include directories relative toplugin_dir
that will be added to the build fileadditional_library_dirs
: (Optional list of strings default=[]) List of additional library directories relative toplugin_dir
that will be added to the build fileadditional_libs
: (Optional list of strings default=[]) List of additional libraries needed for compilation that will be added to the build filepreprocessor_defines
: (Optional list of strings default=[]) List of preprocessor definitions to add to the build file (Note: the build system will automatically addx_EXPORTS
and the relevant preprocessor defines forboost
andtbb
for USD)depends_on
: (Optional list of strings default=[]) List of plugins this one depends on so the build files generated have the right orderingschema_file
: (Required string) Path relative to${root}
where theschema.usda
file can be found (including theschema.usda
part)is_codeless
: (Optional bool default=false) True if the schema should be a codeless schema, false otherwisemodule_dir
: (Optional string default="x") Path relative toinstall_root
where the built Python module and Python module files will be placedpymodule_cpp_files
: (Optional list of strings default=[]) List of C++ files relative toplugin_dir
that are required for compiling the Python modulepymodule_files
: (Optional list of strings default=["generate_dir/init.py"]) List of Python files relative toplugin_dir
that will be copied to theresources_dir
target (preserving sub-directory structure)generate_module_cpp_file
: (Optional bool default=true) Boolean informingrepo_usd
whether or not to generate themodule.cpp
file for the schema plugingenerate_module_deps_cpp_file
: (Optional bool default=true) Boolean informingrepo_usd
whether or not to generate themoduleDeps.cpp
file for the schema plugingenerate_init_py_file
: (Optional bool default=true) Boolean informingrepo_usd
whether or not to generate the__init__.py
file for the schema plugingenerate_buildfile
: (Optional bool *default=generate_plugin_buildfiles
) Boolean informingrepo_usd
to override whatever setting is ingenerate_plugin_buildfiles
globally on a per-plugin basis.
Contributing
The source code for this repository is provided as-is and we are not accepting outside contributions at this time.