Instancing in Hydra 2.0

This is a rather philosophical post about the long term objectives of Hydra 2.0, with instancing used as a case study of sorts, and I’ll start by posing a question: should a Hydra 2.0 renderer rely on the ‘InstancedBy’ schema?

From the schema docs:

Many renderers need to know not what prototypes an instancer has, but rather what instancers a prototype has…

This value is computed based on the instancer topology of instancer prims in the scene.

This is extrinsic data, inherently tied to how much of the scene has been processed, and so isn’t something that would be relied upon by a consumer that expects scene graph data to be static during progressive evaluation, and would not want the entire scene to be processed in order to produce definitive data for a given prim.

The schema has a quite reasonable historical justification (in the context of both USD scene evaluation and the Storm renderer), but to me it seems inappropriate in the Hydra 2.0 ecosystem. It’s expensive to provide (being heavy on book-keeping), and is more suited to evaluation at the point of scene graph consumption: renderers are perfectly able to do this themselves*.

As I understand it, a generic Hydra filtering scene index (HdInstancedBySceneIndex) existed precisely to provide ‘instancedBy’ data as part of the scene flattening process for Hydra 1 render delegates, but interestingly this was removed (perhaps due to performance concerns?) with the introduction of USD-specific instancing scene indices. These are part of the pre-merge scene index bundle, meaning USD scene instancing isn’t really open for manipulation in the subsequent pipeline. (They’re also forced to work around a limitation in the Hydra 1 scene delegate instancing API that mandates a single instancer for any given prototype prim, but that is an aside.)

The suggestion here, then, is that hydra renderers (currently render delegates) move away from relying on ‘instancedBy’ data in favour of ‘instancerTopology’ and direct scene graph access. One would assume that compatibility could be provided via a generic scene index in the vein of HdInstancedBySceneIndex, but its removal suggests there are reasons to avoid this.

Assuming this proposal is actually aligned with the goals of Hydra 2.0, do we think there is a path to consensus?

* There is one additional piece of information that I think would be beneficial as part of a core Hydra schema: designation of a prim hierarchy as being a prototype (instance source) that is not itself part of the rendered scene. Conceptually, this is equivalent to marking a prim hierarchy invisible at a point above the prototype root, rather than at the root, since visibility would ideally be respected at any point in an instantiated hierarchy. This concept will be familiar to those with experience of instancing in Katana.

One could also argue for an ‘instance ID’ attribute in a Hydra schema as a generic way of indicating to a renderer that it can perform its own instance aggregation, rather than creating point instancers that are dependent on extent of scene processing.

Is there merit in namespacing Hydra schemas that are either Hydra 1 or Hydra 2 specific?

Hey Daniel,

Fun question! :). To define my terms: the two dominant modes of instancing I can think of are vectorized instancing, as exemplified by point instancers, and reference instancing (e.g. “I am a copy of that prim”), as exemplified by USD composition instancing. (Convenient that USD provides both!).

In Hydra we’ve leaned hard into vectorized instancing for a few reasons. In the renderers we maintain (Storm, HdPrman), the vectorized format tends to be a much better representation of the rendering object model (e.g. an instanced draw call, or an instanced BVH node); and additionally, vectorizing instances at the top of our data pipeline can reduce the prim count dramatically, cutting down on hydra bookkeeping overhead. With the large instance counts and specific instance topologies we see in some of our scenes, this latter point can be a big deal.

Vectorized instancing can be a pain to work with; in particular, for things like collection-based modifiers (pruning, material assignments), traversing the hydra scene in the native USD namespace and reading/writing per-instance attributes is currently quite difficult. We’ve had discussions internally about writing utilities to assist with that traversal, along the lines of the HdSceneIndexPrimView, and think this would help quite a bit. As you point out, vectorized instancing also requires full knowledge of the scene. This isn’t an issue for us when we’re reading from a UsdStage, which is our main concern, but could be an issue for other scene graphs.

As far as “instancedBy” on a prim vs “instancerTopology” on an instancer, that’s just flipping a relationship and caching the result. If you have a specific argument for why we shouldn’t do that, I’m curious to hear, but we’ve found computing “instancedBy” makes things easier to implement and faster.

We did try to keep the instancing transformations isolated to a few UsdImaging scene indices specifically so folks could prototype other instancing algorithms; although adding reference instancing as a concept to hydra might require threading it through a bunch of other scene indices as well. As a warning with USD specifically, resolution of composition instancing, UsdGeomPointInstancer prototype semantics, and the “cards”/drawMode feature are somewhat entangled.

tl;dr: vectorizing referenced instances early in the pipeline and computing “instancedBy” remain our plan in Hydra 2, but I hope the system is flexible enough for you to try other approaches, and this topic has a ton of depth and you all have a bunch of accumulated experience and I’m happy to keep chatting about it.