Referencing Layers
VERIFIED ON USD VERSION 21.08
Setup Python
This tutorial will walk you through referencing the simple stage that we created in the previous exercises into a new stage. The HelloWorld.usda that we'll use as our starting point and all the code for this exercise is in the extras/usd/tutorials/referencingLayers folder.
- Author the defaultPrim metadata on the layer that you want to reference. This is the name of the root prim that will be referenced. If it is not authored here, then the referencing client must specify the root prim path it wants from the referenced layer. We also want to author a transformation on the default root prim, so that we can override it later; to do this we use the UsdGeomXformCommonAPI schema, which we will discuss further, later.
from pxr import Usd, UsdGeom stage = Usd.Stage.Open('HelloWorld.usda') hello = stage.GetPrimAtPath('/hello') stage.SetDefaultPrim(hello) UsdGeom.XformCommonAPI(hello).SetTranslate((4, 5, 6)) print stage.GetRootLayer().ExportToString() stage.GetRootLayer().Save()
produces
#usda 1.0 ( defaultPrim = "hello" ) def Xform "hello" { double3 xformOp:translate = (4, 5, 6) uniform token[] xformOpOrder = ["xformOp:translate"] def Sphere "world" { float3[] extent = [(-2, -2, -2), (2, 2, 2)] color3f[] primvars:displayColor = [(0, 0, 1)] double radius = 2 } }
-
Now let's create a new stage to reference in HelloWorld.usda and create an override prim to contain the reference.
refStage = Usd.Stage.CreateNew('RefExample.usda') refSphere = refStage.OverridePrim('/refSphere') print refStage.GetRootLayer().ExportToString()
produces
#usda 1.0 over "refSphere" { }
All of the previous prims we had created are defs, which are concrete prims that appear in standard scenegraph traversals (i.e. by clients performing imaging, or importing the stage into another DCC application).
By contrast, an over can be thought of as containing a set of speculative opinions that are applied over any concrete prims that may be defined in other layers at the corresponding namespace location. Overs can contain an opinion for any property, metadatum, or any prim composition operator. For example, an over can non-destructively express a different opinion for the transform and displayColor attributes above.
-
Let's reference in the stage from HelloWorld.
refSphere.GetReferences().AddReference('./HelloWorld.usda') print refStage.GetRootLayer().ExportToString() refStage.GetRootLayer().Save()
produces
#usda 1.0 over "refSphere" ( prepend references = @./HelloWorld.usda@ ) { }
In this simple example, we are using (an effectively absolute) file path to reference the layer—in practice, the layer identifier given to Usd.References.AddReference() would be a string that a path resolver and scene description file format would process to populate the actual scene description. Both path resolvers and file formats can be implemented as plugins to customize site-specific behavior—there is nothing that requires USD layers to be physical files on disk.
The code in USD/extras/usd/examples/usdObj/ shows how to bring in OBJ mesh topology as a USD file format.
Note that since we authored defaultPrim in HelloWorld.usda, we only need to specify the root layer we want to reference, and it is inferred that we will be bringing in the scenegraph contents rooted at /hello into our /refSphere. If we usdview our exported RefExample.usda, we can see the composed result.
If it were unselected in the namespace browser, usdview would show refSphere in orange to indicate that it is a referencing point on our stage. Our screenshot shows refSphere's row selected, however, to show both what our overridden transformation looks like as attributes, and to note in the Meta Data inspector that the reference and its target are listed. Note also that there is no prim named "hello" since it has been referenced into /refSphere. -
Let's re-set the transform on our over to the identity.
refXform = UsdGeom.Xformable(refSphere) refXform.SetXformOpOrder([]) print refStage.GetRootLayer().ExportToString()
produces
#usda 1.0 over "refSphere" ( prepend references = @./HelloWorld.usda@ ) { uniform token[] xformOpOrder = [] }
What Just Happened???
The UsdGeomXformable schema is component-based, allowing you to specify a single 4x4 matrix, or an unlimited sequence of translate, rotate, scale, matrix, and (quaternion) orientation "ops". Each xformable prim has a builtin xformOpOrder attribute that specifies the order in which the ops are applied. By explicitly setting the ordering to an empty list:
refXform.SetXformOpOrder([])
we are telling the schema to ignore any ops, even if authored, effectively setting the transformation to the identity. We could also have explicitly authored an identity matrix, or set all existing, composed op attributes to their identity values. For a complete explanation of Xformable and XformOps, please see the API documentation for UsdGeomXformable
-
Reference in another HelloWorld.
refSphere2 = refStage.OverridePrim('/refSphere2') refSphere2.GetReferences().AddReference('./HelloWorld.usda') print refStage.GetRootLayer().ExportToString() refStage.GetRootLayer().Save()
#usda 1.0 over "refSphere" ( prepend references = @./HelloWorld.usda@ ) { uniform token[] xformOpOrder = [] } over "refSphere2" ( prepend references = @./HelloWorld.usda@ ) { }
We can see that our over has been applied to move the first sphere to the origin, while the second sphere is still translated by (4, 5, 6).
-
Of course, overs can be authored for the actual sphere prims underneath the reference as well. Let's color our second sphere red.
overSphere = UsdGeom.Sphere.Get(refStage, '/refSphere2/world') overSphere.GetDisplayColorAttr().Set( [(1, 0, 0)] ) print refStage.GetRootLayer().ExportToString() refStage.GetRootLayer().Save()
Note that we don't need to call OverridePrim again—because /refSphere2/world already has a presence in the composed scenegraph, upon calling Set() on a Usd.Attribute, the USD API automatically creates an over for it if one doesn't already exist in the current authoring layer.
#usda 1.0 over "refSphere" ( prepend references = @./HelloWorld.usda@ ) { uniform token[] xformOpOrder = [] } over "refSphere2" ( prepend references = @./HelloWorld.usda@ ) { over "world" { color3f[] primvars:displayColor = [(1, 0, 0)] } }
-
We can also flatten out the composed results—all of the printouts of the scene description above were of the root layer upon which we were performing our authoring. If we call ExportToString() or Export() on the UsdStage itself, we'll print or save out the flattened scene description, respectively.
Definition: flattening
When we use the term flattening we generally mean producing a single Layer of scene description that contains all of the "composed data" from a set of inputs, and retains no composition operators (such as references, payloads, inherits, variants, sublayers, and activations). UsdStage::Flatten(), which flattens an entire stage (and is used by Export() and ExportToString()) is the only basic form of flattening we currently provide, though we hope to expand that in the future to flattening subtrees of a stage, as well as just selected layers in a layerStack.
print refStage.ExportToString()
#usda 1.0 ( doc = """Generated from Composed Stage of root layer RefExample.usda """ ) def Xform "refSphere" { double3 xformOp:translate = (4, 5, 6) uniform token[] xformOpOrder = [] def Sphere "world" { float3[] extent = [(-2, -2, -2), (2, 2, 2)] color3f[] primvars:displayColor = [(0, 0, 1)] double radius = 2 } } def Xform "refSphere2" { double3 xformOp:translate = (4, 5, 6) uniform token[] xformOpOrder = ["xformOp:translate"] def Sphere "world" { float3[] extent = [(-2, -2, -2), (2, 2, 2)] color3f[] primvars:displayColor = [(1, 0, 0)] double radius = 2 } }