All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
UsdUtils: USD Utilities

Overview

UsdUtils contains utility classes and functions for managing, inspecting, editing and creating USD assets. The high-level grouping of classes and functions is as follows:

  • Authoring provides functionality for copying metadata between layers.
  • Conditionally abort diagnostic delegate provides a utility that can be used to abort operations for a non fatal USD error or warning emitted from Tf's diagnostic management system by operating on inclusion/exclusion rules defined for this delegate.
  • Introspection provides functionality for understanding various characteristics of a UsdStage including memory usage, prim counts, prototype counts and more.
  • Pipeline provides utilities for establishing pipeline conventions.
  • complianceChecker.py provides a set of Python classes and methods used for checking the compliance of a given USD asset or USDZ package.

User Processing Functions

Localization routines can be customized by supplying your own processing function which will be invoked as asset paths are discovered during dependency traversal.

Processing functions are able to perform a number of tasks which have an effect on the resulting output:

  • Modify an asset path to contain a new value.
  • Add additional dependencies to be included in the output.
  • Remove an asset path and/or dependencies altogether from the output.

Creating a processing function allows you to create customized output without having to write dependency discovery and traversal code.

When writing a processing function it is important to keep in mind that the intention is to modify the current asset path only. Modifying the layer containing the path during processing may result in assets that behave unexpectedly or fail to load.

Defining A Procession Function

A user processing function is called for each asset path that is discovered during recursive traversal of a root asset layer. For each path, the function will be passed the following parameters:

Name Type Description
layer SdfLayerHandle The layer containing the discovered asset path. In the case that the localization method was called with editInPlace=false this will be the original, unmodified layer.
dependencyInfo UsdUtilsDependencyInfo Contains authored and additional path information for this dependency

The return value of the processing function communicates back to the system any changes that need to be made to the asset path. In C++ your function will return an UsdUtilsDependencyInfo struct. In Python, your function will return a UsdUtils.DependencyInfo object.

Here's an example "identity" processing function that just returns the unmodified input in C++:

ProcessingFunc(
const SdfLayerHandle &layer,
UsdUtilsDependencyInfo &dependencyInfo)
{
return dependencyInfo;
}
Class containing information from a processed dependency.

and in Python:

def ProcessingFunc(layer, dependencyInfo):
return dependencyInfo

After a processing function has been called, the system looks at the returned asset path. If it is empty, then the reference to that path is removed, otherwise the new value is placed in the layer. Additionally, each item in the dependencies array is added to the resulting package and enqueued for recursive traversal.

Modifying AssetPaths and Dependencies

A common use for a processing function is to perform a transformation on an asset path and its related dependencies. For example, a processing function could be used to convert JPG files to PNG files.

USD:

def "Example"
{
asset imageFile = @./image.jpg@
}

C++:

ProcessingFunc(
const SdfLayerHandle &layer,
UsdUtilsDependencyInfo &dependencyInfo)
{
std::filesystem::path path(dependencyInfo.assetPath);
if (path.extension() == ".jpg") {
path.replace_extension(".png");
ConvertToPng(dependencyInfo.assetPath, path);
return UsdUtilsDependencyInfo(path);
}
return dependencyInfo;
}

Python:

def ProcessingFunc(layer, dependencyInfo):
root, ext = os.path.splitext(dependencyInfo.assetPath)
if ext is ".jpg":
pngPath = root + ".png"
ConvertToPng(assetPath, pngPath)
return UsdUtils.DependencyInfo(pngPath)
return dependencyInfo

It is important to note that a coding error will be issued if a function modifies an asset path that is contained in an existing package. You may use the SdfFileFormat::IsPackage and ArIsPackageRelativePath methods on the layer reference passed into the processing function to determine if you are operating on such a layer.

Another useful application of processing functions is to support transient dependencies. Using the OBJ file format as an example, a processing function which naively includes .mtl files with a corresponding base name to their .obj counterparts could be written as:

USD:

def "Obj"
{
asset teapot = @./teapot.obj@
}

C++:

ProcessingFunc(
const SdfLayerHandle &layer,
UsdUtilsDependencyInfo &dependencyInfo)
{
std::filesystem::path path(assetPath);
if (path.extension() == ".obj") {
path.replace_extension(".mtl");
return UsdUtilsDependencyInfo(dependencyInfo.assetPath, {path});
}
return dependencyInfo;
}

Python:

def ProcessingFunc(layer, dependencyInfo):
root, ext = os.path.splitext(dependencyInfo.assetPath)
if ext is ".obj":
return UsdUtils.DependencyInfo(dependencyInfo.assetPath, [root + ".mtl"])
return dependencyInfo

Removing Asset paths

In some cases it may be desireable to exclude assets from localization. This can be accomplished by ensuring that the assetPath of the UsdUtilsDependencyInfo object returned from the processing function is the empty string.

For example, the following function would exclude all assets with a file extension of ".txt":

C++:

ProcessingFunc(
const SdfLayerHandle &layer,
UsdUtilsDependencyInfo &dependencyInfo)
{
std::filesystem::path path(dependencyInfo.assetPath);
if (path.extension() == ".txt") {
}
return dependencyInfo;
}

Python:

def ProcessingFunc(layer, dependencyInfo):
root, ext = os.path.splitext(dependencyInfo.assetPath)
if ext is ".txt":
UsdUtils.DependencyInfo()
return dependencyInfo