What are "inert" prims?


I need to handle notifications coming in from “UsdNotice::ObjectsChanged”

I am struggling to understand these flags in SdfChangeList::Entry:

        // SdfPrimSpec add/remove
        bool didAddInertPrim:1
        bool didAddNonInertPrim:1;
        bool didRemoveInertPrim:1;
        bool didRemoveNonInertPrim:1;

My initial understanding was that inert prims would not contribute any opinions in the composed stage.
With that understanding, I thought that receiving a “didAddInertPrim” would not mean that a prim was actually added, in the composed stage.

However, that doesnt seem to be the case, I get didAddInertPrim flags even though prims actually end up in the composed result.

What am I missing?

Thanks alot!

Doing a bit of code spelunking, the main point where “inert” seems to be passed into spec creation functions is here. Directly pulling how the comments describe inert:

// Prims are considered inert if they are an ‘over’ with
// no typename.

// Properties are considered inert if they are custom.

EDIT: To add more detail, the RemovePrimIfInert function also mentions that inert is anything that does not contribute opinions. I’m not sure what you’re encountering and if it’s still at odds with these definitions, but even if a prim spec does not contribute opinions (very roughly, no metadata or properties are set), it will be composed into the stage as an “empty” UsdPrim.

Thanks for your answer!

Right, i also saw this comment “Prims are considered inert if they are an ‘over’ with
no typename.”. But I took this as one example of inert prims, not the definition of what inert prims are.

In anycase, that’s not what I am seeing - I am just adding a capsule onto an anonymous layer, and i get an didAddInertPrim = true, no "over involved.

I did learn something though : “does not contribute opinions (very roughly, no metadata or properties are set), it will be composed into the stage as an “empty” UsdPrim”

I thought that “there is a capsule at path x/y/z” would in itself be an opinion, or at least just the type being specified, not the case?
If not, then indeed, my capsule is 100% empty :

def Capsule “Capsule1”

And so maybe it indeed does not contribute an opinion, and qualifies as an inert prim?

Thanks again!

Your understanding of inert prims is correct, but there’s a subtlety as to why you’re seeing the capsule being reported as an inert prim.

Just to state it: An inert prim spec in an SdfLayer is one that provides no metadata or property opinions and also does not define a prim on the UsdStage. The idea is that removing inert prim specs would have no effect on the composed values or default traversal of the stage (which only includes “defined” prims). The canonical example is empty “over” prim spec, like:

# Created via SdfCreatePrimInLayer in C++ or Sdf.CreatePrimInLayer in Python
over "IAmInert"

If this was in a layer that was loaded onto a UsdStage, /IAmInert would not be considered “defined”, so it would not be discovered in a default traversal of the stage via e.g. UsdStage::Traverse. In that sense, it doesn’t contribute opinions on the stage. However, if you went looking for it explicitly via UsdStage::TraverseAll or GetPrimAtPath you would find it, so in that sense it is still composed into and available on the stage.

So back to the original question as to why the capsule is being reported as inert. I’m assuming you’re creating the capsule via something like UsdGeomCapsule::Define(stage, ...).

The SdfChangeList::Entry you’re looking at is a record of the operations done at the SdfLayer level. Define batches together a bunch of these operations so they show up in the same Entry (see here). The first operation is the creation of an empty “over”, which sets the didAddInertPrim flag. The next operations set the specifier and typename, which also get recorded. Taken together, these operations do create a non-inert prim spec that defines a prim on the UsdStage. But since the Entry object records the individual operations, you see the didAddInertPrim from the first operation.

UsdStage has logic to digest all of this to update itself as sparsely as possible, but in general looking directly at the SdfChangeList::Entry can get a little tricky. Was there a particular reason why you needed to look at that object directly instead of relying on the resync provided by the ObjectsChanged notice?

1 Like

Thanks alot, that makes alot of sense.

I am fixing a defect in existing code in maya-usd - it does look at resync paths in objectChanged, but then also at the change list for more granularity, as I understand it. My initial attempt did not work, because I didnt expect the “capsule is inert” case, hence my question.

Is there a better way to figure out exactly “what” happened at a resync’ed path?

This code basically translates USD notifications, to “UFE” notifications. Which is an abstraction layer in maya.

It’s this bit here https://github.com/Autodesk/maya-usd/blob/dev/lib/usdUfe/ufe/StagesSubject.cpp#L451

And here is my PR fixing the problem we had : EMSUSD-266 Fixed bad USD/UFE notifications by deboisj · Pull Request #3278 · Autodesk/maya-usd · GitHub

Thanks again.

Hmm, unfortunately at the moment I can’t think of anything purely within USD itself. If the maya-usd code itself kept track of prims it’s previously seen it could reconcile its cache with the UsdStage whenever the resync notice was received. But otherwise, we’d need to add something to the notice to flag whether a resync caused a prim to come into existence or be removed from the stage.

No problem, I was able to fix my problem in the end, I just wanted to understand why I was seeing what I was seeing. Your answer made that clear. Thank you.