Generating New Schema Classes
VERIFIED ON USD VERSION 0.8.5
There are a couple of prerequisites to dealing with schema generation in USD.
- usdGenSchema, our tool for generating C++ classes from a schema.usda file requires the jinja2 template substitution module and argpase modules be installed and available in your python syspath.
- Ensure that you have setup your python environment properly, so it can find USD python modules. We'll refer to the install location of your USD build with USD_INSTALL_ROOT, this is determined in the build with the cmake flag, -DCMAKE_INSTALL_PREFIX.
|PYTHONPATH||This is a path list which Python uses to find modules.||$PYTHONPATH:USD_INSTALL_ROOT/lib/python/|
For more information see our page on Advanced Build Configuration.
The files used in this tutorial are available in USD/extras/usd/examples/usdSchemaExamples/. The objective of this tutorial is to introduce the user to various types of schema classes and to provide instructions for generating, compiling and using them. For a detailed description of schema classes and the various options that usdGenSchema provides for customizing them, see API documentation for generating schemas
What is a Schema Class?
A schema class is simply a container of a UsdPrim that provides a layer of specific, named API atop the underlying scene graph. USD provides a code generator script called 'usdGenSchema' for creating new schema classes. For more info on the script and all of the options it provides see the references section below.
UsdModelAPI, UsdGeomImageable, UsdGeomMesh etc. are examples of schema classes generated using the script. There are other schemas in USD/pxr/usd/lib/usd under usdGeom, usdRi, usdShade and more!
Types of Schema Classes
copied from the API documentation...
Schema classes are classified into the following two types:
IsA schema - An IsA schema can impart a typeName to a prim in addition to providing an interface to a prim's qualities. Every IsA schema must derive from the core class UsdTyped, which is the base class for all typed schemas. Furthermore, an IsA schema can be concrete or non-concrete. An IsA schema will be concrete (or instantiable) if its schema declaration provides both a name for the schema (in quotes) and a typeName in the schema.usda file in which it is defined. A non-concrete (abstract) IsA schema provides only a name for the schema, and hence cannot be instantiated; non-concrete schemas exist to serve as super-classes for related sets of concrete IsA schemas. UsdGeomImageable is an example of a non-concrete IsA schema. UsdGeomScope is an example of a concrete, typed IsA schema.
API schema - An API schema provides an interface to a prim's qualities, but does not specify a typeName for the underlying prim. The prim's qualities include its inheritance structure, attributes, relationships etc. Since it cannot provide a typeName, an API schema is considered to be non-concrete. As a convention, the C++/python class name for an API schema must end with "API". In core USD, UsdModelAPI is an example of an API schema; UsdRiMaterialAPI is an example from our RenderMan schema module, which adds/extracts RenderMan-specific shading information from a generic UsdShadeMaterial-typed prim. Also by convention (with which usdGenSchema can help), the properties that "belong" to an API schema are typically namespaced with the base-name of the schema, camelCased. For example, UsdRiMaterialAPI::CreateSurfaceAttr() will create an attribute named outputs:ri:surface. API schemas are classified into the following two types:
- Non-applied API schemas - If an API schema only provides an interface to certain core bits of metadata (like UsdModelAPI, which sets model kind and UsdClipsAPI, which sets value-clips related metadata) or if there is no use of recording the application of the API schema on a prim (for the purpose of interchange), we make it a non-applied API schema. Examples of non-applied API schemas include UsdModelAPI, UsdClipsAPI, UsdShadeConnectableAPI and UsdGeomPrimvarsAPI. Typically, non-applied API schemas can apply to any prim-type (eg, UsdClipsAPI) or to a known fixed set of prim types, like in the case of UsdShadeConnectableAPI which is only applicable to Shaders and NodeGraphs.
Applied API Schemas - If there is a need to record and discover whether an API schema has been applied to a prim, we make it an applied API schema. In general, API schemas that add one or more properties to a prim should be tagged as applied API schemas. A public Apply() (or private _Apply()) method is auto-generated for applied API schemas. Once an API schema has been applied to a prim, prim.HasAPI<APISchemaType>() will return true. An applied API schema must be applied to a prim via a call to this method, for the schema object to evaluate to true when converted to a bool using the explicit bool conversion operator. Examples of applied API schemas include UsdCollectionAPI, UsdGeomModelAPI and UsdGeomMotionAPI.
Applied API schemas are futher classified into the following two sub-categories:
- Single-Apply API Schemas - Applied API schemas that can only be applied once to a prim. For example: UsdGeomModelAPI and UsdGeomMotionAPI.
- Multiple-Apply API Schemas - Applied API schemas that can be applied multiple times on the same prim with different instance names. For example, UsdCollectionAPI, which has to be applied once per-collection owned by a prim.
The definition of an IsA schema is published, at runtime, into an introspectable "schema definition registry", which is consulted by core Usd when performing property value resolution (i.e. retrieving a property's value at a given UsdTime). This allows IsA schemas to provide fallback values for their properties, i.e., a value that the property will possess, even when none has been authored. Because the definition registry is keyed by prim typeName, a prim can "be" at most (or IsA) a single type, whereas a prim can host data for any number of API schemas, which cannot provide fallback values.
The author of an API schema has to decide on the type of API schema at the time of its creation by setting token-valued customData entry 'apiSchemaType' in the schema definition. It can be set to one of 'nonApplied', 'singleApply' or 'multipleApply'. When unspecified, the fallback apiSchemaType for an API schema is 'singleApply'. An API schema can only inherit from another compatible API schema with matching customData["apiSchemaType"] or from "/APISchemaBase" directly. This is enforced by the schema code generation script 'usdGenSchema'.
Although we will not cover it in this tutorial, you can add (and we have for many of the core schemas) custom methods to any generated IsA or API schema that will be preserved if/when you need to re-run usdGenSchema. Custom methods are handy for providing computations, or authoring operations that require coordinated authoring of more than a single value on a property at once.
Schema Generation Prerequisites
The schema generation script 'usdGenSchema' is driven by a USD layer (typically named schema.usda). Every schema.usda layer must meet the following requirements in order for generated code to compile and work with USD core successfully.
- Must specify the libraryName as layer metadata.
- usd/schema.usda must exist in the layer stack, not necessarily as a direct subLayer.
- Schema typenames must be unique across all libraries.
- Attribute names and tokens must be camelCased valid identifiers.
In our examples, we'll use the following as the base layer (or starting point) for creating new schema classes in order to satisfy the first two requirements above.
Example Typed, Non-Concrete, IsA Schema
A simple non-concrete IsA schema prim with one attribute and one relationship would look as follows. The schema is Typed, but a "SimplePrim" cannot be instantiated on a UsdStage - it is likely a base-class for other, concrete schemas.
Example Concrete IsA Schema
The following is an example of a typed IsA schema class. It derives from the non-concrete </SimplePrim> defined above, specifies a concrete typeName 'ComplexPrim' and adds a string attribute with a fallback value.
Example Applied API Schema
The following is a simple example of an API schema that provides API for manipulating three custom double valued attributes. Note again that API schemas are not allowed to specify a fallback value for the attributes. Note also that API schemas are distinguished from Typed schemas in that they must derive from APISchemaBase.
All of the above schema classes are available in the schema.usda file in extras/usd/examples/usdSchemaExamples/. You can run usdGenSchema to generate all the necessary files. See below for the list of files generated (or edited if they already exist).
Compiling the Schema Prims
To rebuild the plugin, simply go to the root of your build directory and run.
That should be it. To test that the plugin was installed correctly, create a usd file named Test.usda with the following content:
You should be able to load the above usda file in usdview without warnings or errors.
Using the Schema Classes
The following C++ code loads the above test scene, constructs schema prims and uses the API provided by schema code generation.
The following python code loads the above test scene, constructs schema prims and uses the API provided by schema code generation.