docs/tut_referencing_layers.rst
.. include:: rolesAndUtils.rst
.. include:: tut_setup_version_badge.rst
This tutorial walks you through referencing the stage that we created in the
previous tutorials into a new stage. The :filename:HelloWorld.usda that we
will use as our starting point and all the code for this exercise is in the
:filename:extras/usd/tutorials/referencingLayers folder.
#. Author the :usda: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 :usdcpp:UsdGeomXformCommonAPI schema <UsdGeomXformCommonAPI>,
which we will discuss further, later.
Copy :filename:extras/usd/tutorials/referencingLayers/HelloWorld.usda to
a folder of your choice. In that folder, create and run a new Python script
with the following code:
.. code-block:: python
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()
This should modify your copied :filename:HelloWorld.usda to look like the
following:
.. code-block:: usda
#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. In your Python script add the following code and run the script.
.. code-block:: python
refStage = Usd.Stage.CreateNew('RefExample.usda')
refSphere = refStage.OverridePrim('/refSphere')
print(refStage.GetRootLayer().ExportToString())
This will output:
.. code-block:: usda
#usda 1.0
over "refSphere"
{
}
All of the previous prims we had created are :usda: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 :usda: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 in a composed
stage. Overs can contain opinions for any property, metadata, or prim
composition operators. 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. Update your script to add a reference to "refSphere":
.. code-block:: python
refSphere.GetReferences().AddReference('./HelloWorld.usda')
print(refStage.GetRootLayer().ExportToString())
refStage.GetRootLayer().Save()
This will produce (in :filename:RefExample.usda):
.. code-block:: usda
#usda 1.0
over "refSphere" (
prepend references = @./HelloWorld.usda@
)
{
}
.. admonition:: Asset Path Resolver and File Format Plugins
In this example we use a filename to reference the layer. In practice,
the layer identifier passed to :python:`Usd.References.AddReference()` can
be any string that a path resolver plugin can resolve and a scene
description file format plugin would process to populate the actual scene
description. USD supports user-implementable asset path resolver and file
format plugins to allow site-specific customization and pipeline
integration. USD does not require that layers be files on disk. See
`the Ar library documentation <api/ar_page_front.html>`__ for more about
asset resolvers, and see the code in
:filename:`USD/extras/usd/examples/usdObj/` for an example file format
plugin.
Note that since we authored :usda:defaultPrim in
:filename:HelloWorld.usda in step 1, 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 :sdfpath:/hello into our
:sdfpath:/refSphere.
Running :program:usdview on the exported :filename:RefExample.usda shows
the composed result.
.. image:: http://openusd.org/images/tut_referencing_layers_refexample.png
If it were unselected in the namespace browser, usdview would show
:sdfpath:/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 :sdfpath:/refSphere.
#. Let's reset the transform on our :usda:over to the identity. Add the
following to your script:
.. code-block:: python
refXform = UsdGeom.Xformable(refSphere)
refXform.SetXformOpOrder([])
print(refStage.GetRootLayer().ExportToString())
This should output:
.. code-block:: usda
#usda 1.0
over "refSphere" (
prepend references = @./HelloWorld.usda@
)
{
uniform token[] xformOpOrder = []
}
What just happened?
The UsdGeomXformable <api/class_usd_geom_xformable.html#details>_
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 :usda:xformOpOrder
attribute that specifies the order in which the ops are applied. By
explicitly setting the ordering to an empty list as in:
:python: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 :code:Xformable and
:code:XformOps, please see the API documentation for UsdGeomXformable <api/class_usd_geom_xformable.html#details>_
#. Update your script to add an additional HelloWorld reference.
.. code-block:: python
refSphere2 = refStage.OverridePrim('/refSphere2')
refSphere2.GetReferences().AddReference('./HelloWorld.usda')
print(refStage.GetRootLayer().ExportToString())
refStage.GetRootLayer().Save()
The updated :filename:RefExample.usda should look like:
.. code-block:: usda
#usda 1.0
over "refSphere" (
prepend references = @./HelloWorld.usda@
)
{
uniform token[] xformOpOrder = []
}
over "refSphere2" (
prepend references = @./HelloWorld.usda@
)
{
}
.. image:: http://openusd.org/images/tut_referencing_layers_xform.png
We can see that our :usda:over has been applied to move the first sphere
to the origin, while the second sphere is still translated by
:code:(4, 5, 6).
#. Of course, :usda:overs can be authored for the actual sphere prims
underneath the reference as well. Let's color our second sphere red.
.. code-block:: python
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
:usda:/refSphere2/world already has a presence in the composed scenegraph.
USD automatically creates an :usda:over when :python:Usd.Attribute.Set()
is called if one doesn't already exist for that prim in the current authoring
layer.
:filename:RefExample.usda should now look like:
.. code-block:: usda
#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)]
}
}
.. image:: http://openusd.org/images/tut_referencing_layers_color.png
#. We can also flatten the composed results. All of the scene description
listings above were of the stage's root layer, where we performed our
authoring. Calling :usdcpp:ExportToString() <UsdStage::ExportToString> or
:usdcpp:Export() <UsdStage::Export> on the :usdcpp:UsdStage itself, will
print or save out flattened scene description, respectively.
flattening
The term flattening generally means producing a single Layer of scene
description that contains the final "composed data" from a set of composed
layers, and retains no composition operators such as references,
payloads, inherits, variants, sublayers, and activations (except
references generated in order to preserve :ref:scene graph instancing <glossary:Instancing>). :usdcpp:UsdStage::Flatten
flattens an entire stage and is used by :code:Export() and
:code:ExportToString(). USD also supports flattening individual
:ref:layer stacks <glossary:LayerStack>. See
:usdcpp:UsdFlattenLayerStack.
.. code-block:: python
print(refStage.ExportToString())
Your script should output the following flattened stage string. Note that
if you've opened :filename:RefExample.usda in :program:usdview you can
get the same flattened stage string by simply entering
:code:print(usdviewApi.stage.ExportToString()) in usdview's interpreter
window.
.. code-block:: usda
#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
}
}