Scenegraph Instancing#
Scene graph instancing enables sharable composed representations of subgraphs of prims called “prototypes”.
Clients of scene graph instancing can reuse “prototype traversal” to reduce memory consumption and speed up computations.
“Prototypes” are internally implicitly derived from a prim’s composition arcs, but explicit “prototype source” scene description can be authored and refined.
Materials and geometry should be encapsulated into instanceable subgraphs.
Editing a specific instance
The instance’s root prim is editable and therefore it can be used to set visibility or transformations. It can also be reparented or grouped in the prim hierarchy. Note: Usually this prim is either an “Assembly” or “Component” kind. Selection modes can be used to make it easier to select these prims.
Editing a prim within a specific instance
Disabling the “instanceable” metadata on the instance permits edits to the content of the instance, i.e., the prims below its root prim.
Editing all instances of a prototype
To edit all instances of a prototype, locate the target of the reference on the instance - the prim path located in the property panel under “references”. Edits to the children of this prim will be propagated throughout the stage to all of its references.
Note
The prototype hierarchy needs to be encapsulated. For example, materials should either be defined within the prototype or they should be referenced into the prototype before they are bound.
What is scene graph instancing?#
OpenUSD’s composition engine provides a unified language for assembling scenes with sparse overrides. For complex scenes assembled through referencing (and other composition arcs), there’s an opportunity to share composed results when granular overrides aren’t required.
Consider a warehouse digital twin with aisles and aisles of shelves. While the contents of the shelves may vary, the actual shelves themselves may be identical. Scene graph instancing lets the composition engine as well as downstream renderers and simulators share the geometric and material representations of the shelves.
The language of scene graph instancing#
OpenUSD frames scene graph instancing around the concepts of “prototype” subgraphs and “instances” of those “prototypes”. Any field of the “instanceable root” prim, composition arcs, transforms, primvars, etc. may vary from its underlying “prototype”. Only the descendant prims of the “instanceable root” are shared as “prototypes”.
In the simplest case of scene graph instancing, an asset is “referenced” with “instanceable” set to true. All additional references to that same asset will share the same underlying composed “prototype”.
“Prototypes” are implicitly derived from the composition arcs specified by the “instanceable root”. If an asset has variant sets, only instances with the same variant selections will share a prototype. If animation is scattered via referencing on instanced assets, only instances with animation layers and offsets will share a prototype.
Instanceable prim hierarchies can be deinstanced by setting instanceable=False if sparse overrides are needed downstream.
class "prototype_sources" (kind="group") {
def Xform "Shelf" (kind="component") {
def Scope "Geometry" { … }
def Scope "Materials" { … }
}
}
def Scope "Warehouse" (kind="assembly") {
def "Shelf_1" (references = </prototype_sources/Shelf>
instanceable = True) { … }
def "Shelf_2" (references = </prototype_sources/Shelf>
instanceable = True) { … }
def "Shelf_n" (references = </prototype_sources/Shelf>
instanceable = True) { … }
}
Instancing optimizes scene graph traversal#
As instancing enables scalability in renderers through shared geometric representations, it commonly is described as a memory optimization. However, the composed OpenUSD stage is responsible for resolving the location of values and never has to read the entire geometric representation of the scene into memory. While scene graph instancing generally improves the time and memory required to compose a stage, it primarily enables optimized traversal of the stage.
Consider a script counting the screws in a warehouse with instanced shelves. The naive solution would traverse the entire composed scene, counting each screw. The instancing-aware solution would instead count the screws in each shelf prototype and reuse that count when encountering an instance of the shelf on the stage. A script operating on a warehouse with hundreds of shelves could replace the traversal of hundreds of subgraphs with a simple cache lookup.
Orient scene graph instance structures around traversal cost. Attempting to instance too granular subgraphs may result in more prims and complicate traversal without reaping the performance benefits.
Use composition to support refinable instancing#
OpenUSD’s prototypes are implicit and read only. However, the source scene description of prototypes can be internal references (or targets of specializes and inherits arcs).
Internally refinable instancing is the most efficient and simplest way to provide “explicit sources” for “implicit prototypes”. A root prim (commonly named /prototypes, /prototype_sources, or /sources provides a list of internally referenceable children to internally reference. Internal references are only refinable in a local layer stack. Specializes and inherits arcs can provide refinable targets outside of the local layer stack, but those structures are beyond the scope of this document.
It’s preferred to specify the root “prototype sources” prim as a “class”. This makes the composed descendants “abstract”, and not imageable or traversable by default. The targeted descendant reference will not be abstract. Tools and widgets can then opt into “prototype source” traversal and filtering by adding and removing “PrimIsAbstract” from the default traversal predicate.
Instancing is encapsulation#
A prototype is an encapsulated subgraph. Relationships (like material bindings) on geometry cannot refer to prims that exist outside the prototype. Component models often are a good granularity for instancing as they encapsulate their materials and geometry.
As the targets of binding relationships, materials are often encapsulatable. Asset constructors might reap the most performance benefits from designing instanceable material networks and packages than trying to construct instanceable subgraphs geometry already optimized by file format level buffer deduplication and renderer level mesh deduplication.
Note
In OpenUSD, the specification for collections and collection based material bindings do afford the targeting of instanced prims without technically breaking encapsulation. Support for this across the OpenUSD ecosystem is inconsistent, and its usage is discouraged.
Instances can be naturally spatially varied because transformation operations in OpenUSD are hierarchical. Properties that have computed hierarchical inheritance are expected to work with instancing. For example, an instance with an “invisible” ancestor should never be imaged, regardless of the visibility state of the “prototype”.
Properties that don’t have inheritance semantics must be varied through composition arcs to preserve instancing. While beyond the scope of this document, refinements specified through “inherits” or “specializes” can apply edits to entire classes of instances to avoid generating new prototypes. Variant sets can be varied, but each selection will get its own prototype.