Practical USD: Instances and Variants [3/4] (Patreon)
Content
We can continue to refine and enhance our chess set scene by introducing a few new USD concepts. Let's do it!
First up, instancing. We're all familiar with the concept of using instancing to save memory when creating many copies of an asset in a scene. This workflow often results in huge performance improvements as it allows a DCC to load an asset only once and instance copies for "free" (or very low cost).
USD implements this via its boolean instanceable property. We can use it to improve the memory footprint of our chess scene significantly.
Before we begin, it's important to note one limitation. If a USD instance contains a hierarchy, then all its children are unmodifiable. For example, if we instance an entire pawn Xform, including the pawn mesh, the felt curves and the felt pad, then we wouldn't be able to assign separate materials to each of these child prims. In order to work around this we can simply make sure to instance each child individually.
Let's do this in USD Composer: select each element we want to instance, then tick the instanceable checkbox.
(We can instance the felt parent Xform since the curves and mesh will share the same material and so it's not a problem that the two children will be unmodifiable.)
Save this stage to disk and let's have a look at what USD Composer did:
Some new sections have been added to all the prims we instanced, featuring a new keyword: over. This is another USD specifier, joining def which we learned about in the last article. (There is a third, class, which is the most technical and infrequently used of the three. For our purposes, knowing about def and over only will be enough.)
In this case we can see that our USD file is nondestructively updating our pawn and felt prims by adding new data using the over specifier. You can think of it as "overriding" the attributes of existing prims.
Let's check in to see how much our scene performance has improved after making this simple change. On my computer an instanced version of the scene takes up around 300MB of RAM in usdview, versus a whopping 850MB otherwise. 60% less memory used!
I highly recommended taking advantage of this USD instancing workflow whenever possible. The performance benefits are large and immediately apparent.
A final note on instances before we move on: USD also supports point instancing, which allows scattering objects to points, such as trees on a hill or flowers in a garden. The type of instances we described above, using the instanceable keyword, use a small amount of extra memory for each instance, although it is a tiny fraction of that used by the original geometry. A USD point instancer is even more memory-efficient and is recommended for scenes with millions, billions or even trillions of instances. USD Composer implements point instancing with a paint brush system that will be familiar to Unreal Engine users. We'll cover this briefly in a later installment in this series.
Next, let's look at variants. USD allows us to store many different variations of our scene and switch between them with ease. Let's say we were selling real life chess sets and wanted to render out versions showing every color and material customers could buy. We could easily create a Variant Set and add multiple different material bindings. From there, it's a simple matter of choosing which variant to view via a dropdown list.
Variant Sets can be applied to anything. We could create variants where the pieces are in different positions or the scene has different lighting. We could even replace the geometry entirely! In short, we can have many different versions of our scene all stored in the USD file and accessible in any DCC. (Although, note that material support is still a bit up in the air. USD Composer materials won't render in RenderMan, and so on.)
Using USD Composer, let's quickly create two variants, one with the chess pieces in their starting position and one a few moves into the game. Right click on the pieces Xform and select Edit Variants.
Make a new Variant Set, then create one variant for the home position and one for the moved pieces. You'll have to select all the prims that need to be modified and then click Add Property to include the xformOp:translate and xformOp:rotateXYZ attributes.
If we save this updated stage to disk we can see that the Variant Set created in USD Composer is now present in our plain text USDA file. Note the presence of the over specifier again: our variants are overriding the original position of each prim.
Let's check this same file in usdview and Houdini Solaris. The two poses are present and easily swappable. Our scene now contains multiple different states and is fully portable to any DCC that supports USD. Powerful stuff!
In the next article we'll cover some final advanced concepts to round out our understanding of USD. Click here!