Do primvars apply inside Instances?

I was reading the instancing docs:
https://openusd.org/dev/api/_usd__page__scenegraph_instancing.html#Usd_ScenegraphInstancing_Editing
And just wanted to confirm: when it says:

Properties and metadata (e.g., variant selections) on instance prims can be edited and overridden like any other prim. However, properties and metadata on descendant prims beneath instance prims cannot be overridden.

Does “properties on descendant prims” (illegal) include primvars?
Like in this example on the page, color is just a normal attribute. But what if I wanted it to be a primvar? Or if I wanted to control something else (ID, “casts shadow”, …) via primvar on the prim, or maybe its parent. So I’d be changing an attribute at the level of the prim or higher. Though I’d be expecting to see it impact a descendant.

(My gut instinct is that if it is meant to be observed as an attribute on a descendant prim, like a Mesh, that it wouldn’t observe the primvar, like the Prototype would lock it off? But I’m just guessing.)


We’re working in Houdini Solaris, and we observed in the Scene Graph, it looked like the primvar(related to shadowing) carried down to the descendant prims, but when we rendered, they did not. Though in the Scene Graph, I don’t think we’re seeing the Prototypes either.
We weren’t sure if this was a bug in the renderer?
Or if there was somehow the Scene Graph was generated before generating prototypes? (Though from that page, it looks like it’s handled by UsdStage, so I would have expected prototype generation to just be part of stage composition?)

Hi @SteveHwan

the behaviour you are seeing in Solaris is that in the outliner, the “inheritance” is shown because in USD the constant primvars are always propagated to descendant prims but when scenegraph instancing is in place, then the usd-representation of the primitives doesn’t reflect the hydra-representation of the primitives.

Two separate elements, set as instanceable, in USD, will be translated into a single Hydra HdInstancer with 2 instances.
And the “primvars” are then translated into per-instance primvars (which then it is up to the render delegate to handle them as per-instance primvars now, instead of constant primvars)

And you don’t see extra implicit prototypes in USD because of inherited constant primvars not really contributing to the composition arcs of the descendant prims.

A way to control creation of the implicit prototypes (and so the amount of those to make sure you control the complexity of the scene) is to use inherited-edits with classes, which is the last paragraph in the link you posted:

Although “editing prototypes” is disallowed, USD’s composition arcs can be used to achieve many of the same effects. For example, a consumer could add inherit or specializes arcs to instances, then make edits to the class targeted by those arcs. Those edits would then affect all of the specified instances.

This is an example we are putting together to then release it in the main assets-repo, showing various ways to achieve edits on scenegraph instancing and PointInstancers in USD, to then have a good control on what to expect when rendering.
Again, there are a few things that some render-delegates could do, more than others, but in general this way of applying edits in USD could be a very generic one, if it helps.

Hey, thank you for the answers.

Something I wasn’t sure of -
In that page, it refers to prototype generation being done by the UsdStage, so I thought that was saying that the Prototype generation was done by straight stage composition.
But from what you’re saying above (and also what I kind of suspected), it sounds like Prototype generation is a Hydra operation?

I hadn’t heard of per-instance primvars. Are those stored on the Prototype? Like is the Prototpye holding the inherited primvar varlues for all of the instances? Is “per-instance” an Interpolation type? I don’t see it listed (only see constant, uniform, varying, vertex, faceVarying).

The implicit prototypes (those named _Prototype#) are generated automatically on the USD side, looking at the composition arcs on all those primitives tagged as “instanceable=true” (the instance-sources): same composition-arcs will point at the same implicit prototype.

A more explicit way of instancing is via creating explicit PointInstancers with their own Prototypes.
(and also those PointInstancers Prototypes could be set as instanceable so that they can also point at the implicit prototypes).

Basically, a scene with 2 individual cubes and a PointInstancer with 2 instances of a “cube” prototype, could be all pointing at the same implicit prototype if both cubes and the PointInstancer prototype are instanceable and have same composition arcs.

But when rendering through Hydra, there is a translation(/consolidation) of various parts of the aforementioned scene.

Without any instanceable metadata, the previous scene will translate into Hydra as 2 HdPrims (for the two individual cubes), an HdPrim for the PointInstancer prototype, and an HdInstancer with 2 instances.

With instanceable metadata set on those cubes (and appropriate composition arcs to make a single implicit prototype for all the cubes in the scene), the translation in Hydra generates 2 HdInstancers, one for the two individual cubes, and one for the PointInstancer, and 2 HdPrims, one for the implicit prototype and one for the PointInstancer Prototype.
(There is a longer story about shared prototypes, but we can skip it for now).

So, the important part is that translation of the 2 individual cubes into an HdInstancer with 2 instances.
In this translation, the constant primvars on those cubes are going to be translated into per-instance primvars (which render delegates can query as other per-instance primvars like points, scales, etc.)

Sorry for the long explanation… a whiteboard would have helped :slight_smile:

In the example scene we are building, you can see how, with composition arcs properly setup, you can control the amount of implicit prototypes, as to have a closer match to how many HdPrims and HdInstancers will be created when rendering through Hydra.

Whether you use PointInstancers or individual elements with instanceable-metadata (scenegraph instancing), is a matter of accessibility of the data, and also editability, because on the USD side you would have access to individual “instances” in a different way, with more or less features depending on whether you have individual elements or PointInstancers.
But on the Hydra, in both cases you end up with HdInstancers, which is interesting.

And again, in the scene I’ve provided in that link, you can see both ways of providing edits to individual elements with instanceable metadata and to individual instances of a PointInstancers, and what those two different ways involve.

Solaris has a couple of useful nodes to help you with editing Prototypes, as to make it easier for the artists to create edits transparently.

I hope this adds more clarity ( and not more confusion ) to the matter :slight_smile:

Per-instance primvars for “native instancing” are just constant primvars authored on the instance-prim or any of its ancestors, which will inherit down (anywhere not already authored inside the prototype) when querying for primvars on a “instance proxy” prim on a UsdStage. Like @paoloemilioselva said, in Hydra it is the responsibility of render delegates to gather and apply the per-instance primvars appropriately. It should be the case that both Storm and HdPrman already do so.

… and I’m taking a note here that we should discuss the inheritance behavior of primvars-with-instancing in a more discoverable and direct way!