# ( Hydra 1.0 ) Moving one native instance recomputes transforms for every nested instance

**URL:** <https://forum.aousd.org/t/hydra-1-0-moving-one-native-instance-recomputes-transforms-for-every-nested-instance/3011>\
**Category:** Hydra\
**Created:** [July 28, 2026, 4:22pm UTC](https://forum.aousd.org/t/hydra-1-0-moving-one-native-instance-recomputes-transforms-for-every-nested-instance/3011 "2026-07-28T16:22:04Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![hamed](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.aousd.org/hamed/32/677_2.png) [@hamed](https://forum.aousd.org/u/hamed)\
**Post date:** [July 28, 2026, 4:22pm UTC](https://forum.aousd.org/t/hydra-1-0-moving-one-native-instance-recomputes-transforms-for-every-nested-instance/3011/1 "2026-07-28T16:22:04Z")

</div>

Hi,

I have a fundamental question regarding native instancing in Hydra 1.0.

Specs:

- Maya USD 0.33.0
- OpenUSD 25.11
- Windows

I have an asset that are built out of `instanceable` sub-pieces, and those assets  
then get instanced a lot in a layer. See attached [StressTest\_HierarchyRefs.usda](https://forum.aousd.org/uploads/short-url/cQsS4AiUtk0Rcska0LWPHJGPExQ.usda)

StressTest\_HierarchyRefs.usda is the top layer and contains a four-level chain of references, `instanceable = true` at every level, with a single `UsdGeomCube` at the bottom: **125** towers, **25** floors in each tower, **8** rows in each floor, **8** cubes in each row. In total **166** instance-able prims.

In Maya, when I move one of those instances in the top layer ( e.g Tower\_24 ) the frame rate drops drastically that is almost unusable to interact with the scene. See below

![Tower_Performance_StressTest_HierarchyRefs](https://us1.discourse-cdn.com/flex016/uploads/aousd/original/2X/6/6a115f9616d54e27ff4e8ad3bc892d4a6f342677.gif)

On the other hand, if I reduce the level of instancing and only keep the top layer to be instance able ( see [StressTest.usda](https://forum.aousd.org/uploads/short-url/1k72OkLYGlo2lhkZWj8yTLbci0B.usda) ) then I get a better frame rate ~ 7 fps.

![Tower_Performance_StressTest](https://us1.discourse-cdn.com/flex016/uploads/aousd/original/2X/e/e9405c99bea7636fbe8437ba64752449a9cb5ac1.gif)

I’ve spent sometimes in `UsdImagingInstanceAdapter` and I think I understand  
why, but I’d rather have someone who knows this code tell me whether I’ve read it  
correctly:

I think the first is that a moved instance isn’t tracked individually. Its transform  
lives in an array on the instancer, so the only thing Hydra can be told is that  
the array is stale:

```cpp
// instanceAdapter.cpp:1278, ProcessPropertyChange
// Transform changes to instance prims end up getting folded into the
// "hydra:instanceTransforms" instance-rate primvar.
if (UsdGeomXformable::IsTransformationAffectedByAttrNamed(propertyName)) {
    return HdChangeTracker::DirtyPrimvar;
}

```

Then when an instance is populated, the adapter walks down the whole chain of nested instancers and registers a dependency on every one of them:

```cpp
std::queue<SdfPath> depInstancePaths;
depInstancePaths.push(instancePath);
while (!depInstancePaths.empty()) {
    ...
    index->AddDependency(depInstancerPath, prim);
    index->MarkInstancerDirty(depInstancerPath,
            HdChangeTracker::DirtyPrimvar | HdChangeTracker::DirtyInstanceIndex);
    for (SdfPath const& nestedInstance : depInstancerData.nestedInstances) {
        depInstancePaths.push(nestedInstance);
    }
}

```

Once an instance is dirty, its transform array is rebuilt from scratch, sized to  
the **full flattened count** rather than to whatever actually changed:

```cpp
if (requestedBits & HdChangeTracker::DirtyPrimvar) {
    VtMatrix4dArray instanceXforms;
    if (_ComputeInstanceTransforms(prim, &instanceXforms, time)) {

// instanceAdapter.cpp:721
void Initialize(size_t numInstances) { result.resize(numInstances); ... }

```

\_ComputeInstanceTransformFn::operator()

```cpp
GfMatrix4d xform(1.0);
for (UsdPrim const& prim : instanceContext) { 
   xform = xform * adapter->GetTransform(prim, prim.GetPath(), time, ignoreRootTransform);
}

```

I added some debugging code in `UsdImagingInstanceAdapter::_RunForAllInstancesToDraw`

```cpp

TF_WARN("_RunForAllInstancesToDraw [%s] %s rows=%zu",
        ArchGetDemangled(typeid(Functor)).c_str(),
        instancer.GetPath().GetText(),
        instancerData->numInstancesToDraw);

fn->Initialize(instancerData->numInstancesToDraw);

```

This function is called from multiple sites ( e.g \_ComputeInstanceMapFn, \_PopulateInstanceSelectionFn, \_GetScenePrimPathsFn )

```auto
// Warning: _RunForAllInstancesToDraw [UsdImagingInstanceAdapter::_ComputeInstanceMapFn] /Root/Tower_0 rows=125
// Warning: _RunForAllInstancesToDraw [UsdImagingInstanceAdapter::_PopulateInstanceSelectionFn] /Root/Tower_0 rows=125
// Warning: _RunForAllInstancesToDraw [UsdImagingInstanceAdapter::_ComputeInstanceMapFn] /__Prototype_5/Row_0 rows=25000
// Warning: _RunForAllInstancesToDraw [UsdImagingInstanceAdapter::_PopulateInstanceSelectionFn] /__Prototype_5/Row_0 rows=25000
// Warning: _RunForAllInstancesToDraw [UsdImagingInstanceAdapter::_ComputeInstanceMapFn] /__Prototype_6/Floor_0 rows=3125
// Warning: _RunForAllInstancesToDraw [UsdImagingInstanceAdapter::_PopulateInstanceSelectionFn] /__Prototype_6/Floor_0 rows=3125
// Warning: _RunForAllInstancesToDraw [UsdImagingInstanceAdapter::_ComputeInstanceMapFn] /__Prototype_7/Cube_0 rows=200000
// Warning: _RunForAllInstancesToDraw [UsdImagingInstanceAdapter::_PopulateInstanceSelectionFn] /__Prototype_7/Cube_0 rows=200000
// Warning: _RunForAllInstancesToDraw [UsdImagingInstanceAdapter::_ComputeInstanceMapFn] /__Prototype_7/Cube_0 rows=200000
// Warning: _RunForAllInstancesToDraw [UsdImagingInstanceAdapter::_GetScenePrimPathsFn] /__Prototype_7/Cube_0 rows=200000
// Warning: _RunForAllInstancesToDraw [UsdImagingInstanceAdapter::_ComputeInstanceMapFn] /__Prototype_7/Cube_0 rows=200000
// Warning: _RunForAllInstancesToDraw [UsdImagingInstanceAdapter::_ComputeInstanceMapFn] /__Prototype_7/Cube_0 rows=200000

```

```auto
rows(Tower) = 125 = 125
rows(Floor) = 25 × 125 = 3,125
rows(Row) = 8 × 25 × 125 = 25,000
rows(Cube) = 8 × 8 × 25 × 125 = 200,000

```

Am I interpreting this correctly? does a transform edit on one top-level instance dirty every nested instances, with each one rebuilding its whole `instanceTransforms`?

Any help is appreciated.

[TowerOfCubes\_HierarchyRefs.usda](https://forum.aousd.org/uploads/short-url/cmrcpzo2R4EdOTZkMkRhvXVWcen.usda) (5.6 KB)

[TowerOfCubes.usda](https://forum.aousd.org/uploads/short-url/yvmVSjjcsdiZgszGupJDXxv3mKL.usda) (268.9 KB)

[StressTest\_HierarchyRefs.usda](https://forum.aousd.org/uploads/short-url/cQsS4AiUtk0Rcska0LWPHJGPExQ.usda) (30.2 KB)

[StressTest.usda](https://forum.aousd.org/uploads/short-url/1k72OkLYGlo2lhkZWj8yTLbci0B.usda) (28.5 KB)

[Row.usda](https://forum.aousd.org/uploads/short-url/7XwVYJT95A5jJsCqz1niimHNgth.usda) (1.8 KB)

[Floor.usda](https://forum.aousd.org/uploads/short-url/8AHORHBOHs7vSFTmyfi0tL0Fduf.usda) (1.8 KB)

[Cube.usda](https://forum.aousd.org/uploads/short-url/wF0Nce6FMziEt6hIzaNLPmpSpsv.usda) (118 Bytes)
