Configure Stage - Remove Load Paths from Input

   1110   8   1
User Avatar
Member
30 posts
Joined: Sept. 2023
Offline
Hi!

I'm having a hard time unloading payloads via the Configure Stage node. I have a stage similar to the one in Houdini's USD Asset Building [www.sidefx.com] course, with a few changes - splitting the one payload into two: geo_payload and mtl_payload

Now the hierarchy looks like this:
HiRes_Pig (Kind: group)
|---geo_payload (Kind: component)
|---mtl_payload


I load in HiRes_Pig.usd via the Reference node,
and in a subsequent Configure Stage, I set Load Primitives to "Add and remove primitives to load", and:
a. Set Remove Load Paths from Input to /HiRes_Pig/geo_payload
or
b. %kind:component

If I understand the node documentation correctly, both of these should unload geo_payload. But they are unloading all the payloads.


I must be misusing this feature.. Please see the example file attached. Thanks!
Edited by nd_sliu - Sept. 12, 2024 20:43:03

Attachments:
outliner.png (30.4 KB)
outliner_after_configure_stage.png (157.6 KB)
payload-removal.zip (864.6 KB)

User Avatar
Staff
4525 posts
Joined: July 2005
Offline
USD lets a stage work in two modes: "load all payloads", or "load no payloads". In "load all payloads" mode, you cann't specify a list of payloads to _not_ load. But in "load no payloads" mode, you can specify a list of payloads to explicitly load. When you set the Configure Stage LOP to "Add and remove payloads to load", LOPs recreates the input stage in "load no payloads" mode, but allows you to control the explicit list of payloads to load.

So given this context, this means that "remove load paths" doesn't set a list of paths that should be unloaded (there is no such list). It removes the specified path from the list of paths that should be loaded. If that list starts out empty (load nothing), removing an entry from this empty list does nothing and you are still left with an empty list of paths that should load payloads. So no payloads load.

To get the result that (I think) you want, you must put "/HiRes_Pig/geo_payload /HiRes_Pig/mat_payload" in the "Load Paths", then you can remove "/HiRes_Pig/geo_payload" and get the result you expect. Or cut out the middle step and just put "/HiRes_Pig/mat_payload" in the "Load Paths" parameter.
User Avatar
Member
30 posts
Joined: Sept. 2023
Offline
@mtucker. That totally makes sense. I think I just confused the order of operation in Python with this workflow.
Looks like this is the correct way:


I want to ask a follow-up. I have a stage with nested payloads:


main_stage
|prototypes (payload)
|--sliu_sphere
|--|sliu_sphere_0
|--|--renderable (payload)
|--|sliu_sphere_1
|--|--renderable (payload)
...

Using the same method above, I first set nothing to load, so the stage looks like this at first:


Then, I start loading using primpattern "%nodescendants(%kind:group)". I expect that it would simply load prototypes, but not any of the payloads below. But everything got loaded, including the "renderables"

In the USD Python lib, I can achieve the desired behavior using the code snippet below:
import pxr
from pxr import Usd

filepath = "path-to-example-file/main-stage/asset.usda"  # insert path to stage
stage = Usd.Stage.Open(filepath, load=Usd.Stage.LoadNone)
print("Load None")
for prim in stage.TraverseAll():
    print(prim)

print("___________________")

print("Load Groups")
rules = Usd.StageLoadRules()
for prim in stage.TraverseAll():
    model = Usd.ModelAPI(prim)
    if model.GetKind() == "group" and prim.HasPayload():
        rules.LoadWithoutDescendants(prim.GetPath())

stage.SetLoadRules(rules)

for prim in stage.TraverseAll():
    print(prim)
    

I provided the example stage. Is there an equivalent to this in LOPs?
Edited by nd_sliu - Sept. 16, 2024 20:51:38

Attachments:
nested-payloads.png (41.6 KB)
no-payload.png (9.3 KB)
only-load-groups.png (71.8 KB)
example-stage.zip (44.5 KB)
final.png (104.4 KB)

User Avatar
Staff
4525 posts
Joined: July 2005
Offline
Solaris always does "load with descendants" style payload loading. We don't support "Load without descendants" because we found the implications of this workflow to be fairly confusing... You have to find the exact prim with the payload to load it. You can't just say "load everything from here down". Or if we were to provide both options (with or without descendants), we think that would result in a fairly complicated UI. So we went with the simplest thing that gives what we felt was the "most expected" behavior.

We also generally discourage nested payloads. They can complicate things and rarely provide a significant benefit. Especially in LOPs where we always do "Load with descendants".
User Avatar
Member
30 posts
Joined: Sept. 2023
Offline
Thanks for the insight! For the most part Solaris is faithful to all the features USD provides, but it makes sense why you're leaving this out.
Even though USD allows nested payloads, we also found it to "complicate things and rarely provide a significant benefit" as well 😄
That said, it would be nice to note this in the documentation. I had actually expected the Solaris behavior to be equivalent to "LoadWithoutDescendants"
Edited by nd_sliu - Sept. 18, 2024 16:04:51
User Avatar
Member
30 posts
Joined: Sept. 2023
Offline
Hello again @mtucker! I'm running into case where I need to procedurally unload payloads by their kind after loading them.
Using the simple test case from above, when the PigHead stage is referenced in, we get HighRes_Pig/geo_payload and HighRes_Pig/mtl_payload both loaded by default.

Now I want to remove the geo_payload, so I did the following setup:
1. Create Configure Stage, set Load Primitives to "Load all primitives"
2. Bring HiResPig in via Reference
1. Create Configure Stage, set Load Primitives to "Add and remove primitives to load"
2. Set Remove Load Paths form Input to "/HiRes_Pig/geo_payload" (or ideally "%kind:component")


Unexpectedly, both geo_payload and mtl_payload are unloaded now.

Can you shed some light on this behavior?
Edited by nd_sliu - Oct. 1, 2024 22:07:56

Attachments:
unload-after-load.zip (694.0 KB)
unload-after-loading.png (93.4 KB)

User Avatar
Staff
4525 posts
Joined: July 2005
Offline
This is the same issue again... You're asking the LOP node to "remove" geo_payload from the explicit list of primitive for which you have asked to load the payloads. But by saying "load all primitives" with the first configure stage LOP, you haven't provided a list of primitives whose payloads should be loaded. So you are essentially switching the "load mask" to say "load this specific list of payloads", but the list of payloads to load is empty. Then you're saying "remove this one prim from the list of payloads to load", which does nothing because it's removing that payload from an empty list. So you end up loading nothing.

I'll be the first to admit this is all much more complicated and confusing than it needs to be. I can think of a few ways to make this all behave in a more understandable/expected manner. But this will all take some time to sort out. For now you'll have to figure out how to create an explicit list of payloads to load, and _then_ you can remove geo_payload from that list...
User Avatar
Staff
4525 posts
Joined: July 2005
Offline
Okay, so one piece of this was easy enough that I did it immediately... In 20.5.375, there is a new "%payload" auto-collection which matches any prim with a payload composition arc on it. So in your Configure Stage LOP, you can use "add/remove payloads" mode, put "%payload" in the "load paths from input" and "%kind(component)" in the "remove load paths from input" and get the result that I think you're looking for.
User Avatar
Member
30 posts
Joined: Sept. 2023
Offline
The %payload auto-collection looks like a good workaround. I'll try that out when we upgrade to the next production build. Thanks for the insight!
  • Quick Links