Write out USD with Animated Switch in LOPS?
773 9 2- frame_48
- Member
- 16 posts
- Joined: Feb. 2019
- Offline
Is there a way to have a time dependent LOPs Switch node? We are trying to branch out our main pipe and do some edits of some props, then plug those into a switch node and animate the index parameter to switch between them. However this doesn't work when exporting the USD, it just defaults to index 0.
I tried geometry clips, and pruning as well. Is there a way to force this nodes to be time dependent?
I tried geometry clips, and pruning as well. Is there a way to force this nodes to be time dependent?
- mtucker
- Staff
- 4523 posts
- Joined: July 2005
- Offline
There is no reason this shouldn't "just work". The Switch LOP input index parameter can definitely be animated. The time dependence may disappear downstream if you have a Cache LOP between the Switch and the ROP, but then the Cache LOP would have already cooked the animated switch value. Keep in mind that USD scene graph hierarchy cannot change over time, so if one switch input creates /cube and the other switch input creates /sphere, and your input index is "$F%2", saving out the first two frames will result in a USD file with both /cube and /sphere in it. But the ROP has the "track prim existence to author visibility" which will mark the sphere invisible on frame 1, and the cube invisible on frame 2.
- frame_48
- Member
- 16 posts
- Joined: Feb. 2019
- Offline
- mtucker
- Staff
- 4523 posts
- Joined: July 2005
- Offline
This has nothing to do with the switch, AFAICT. The difference is that on the "doesn't work" side, you have set the Output File to be blank. So the root layer of the stage (the one that adds the BASE_LAY as a sublayer) isn't being written out. So the SETDEC_LAY on the "doesn't work" side is simply not sublayering in BASE_LAY. The simplest fix here is to change the sublayer2 LOP to turn off "Edit Root Layer". This will add the BASE_LAY layer as a sublayer of the SETDEC_LAY layer you are authoring/altering with the cube/sphere/pig LOPs.
- frame_48
- Member
- 16 posts
- Joined: Feb. 2019
- Offline
mtucker
This has nothing to do with the switch, AFAICT. The difference is that on the "doesn't work" side, you have set the Output File to be blank. So the root layer of the stage (the one that adds the BASE_LAY as a sublayer) isn't being written out. So the SETDEC_LAY on the "doesn't work" side is simply not sublayering in BASE_LAY. The simplest fix here is to change the sublayer2 LOP to turn off "Edit Root Layer". This will add the BASE_LAY layer as a sublayer of the SETDEC_LAY layer you are authoring/altering with the cube/sphere/pig LOPs.
Sorry I made the test scene in a rush and forgot to load the BASE_LAY.usd then layerbeak before doing the edits. This scene represents better our current workflow of having a BASE.usd that gets loaded in, edited, then exported as a SET_DEC.usd layer that has an opinion over BASE.usd.
Image Not Found
The newly attached hip file represents better our current workflow and what we are trying to do. I am still just getting the first input of the switch getting written out with or without the configure layer.
Are we just approaching this the wrong way? I'd appreciate some insight if so so we can rethink our worklow! Thanks!
- robp_sidefx
- Staff
- 501 posts
- Joined: June 2020
- Offline
Thanks for the updated scene file. Your approach is conceptually very sensible, but it unfortunately runs into multiple problems.
If you're not interested in the technical details (and I don't blame you if that's the case), I'm attaching a v3 of the scene which should work for you, along with some sticky notes on that changes required to the Edit nodes and the use of a Timeshift LOP.
Okay, now the details.....
The USD ROP, when writing out a multi-frame USD file, needs to stitch together each frame's stage into a single stage containing all the data across all the frames.
A slight aside: the Cache LOP (in "Cache All Frames" mode) does this as well, and is the first debugging tool I usually reach for in cases like yours where you have animation going through a Switch that doesn't survive when writing to disk. The Cache LOP will catch a number of issues (details to follow) and report them as warnings, whereas the USD ROP doesn't (and I'm going to look into why).
For the stitching to work, we only stitch together layers that are "the same". Because you have a Layer Break just before you fan-out and put down the Edit LOPs, each Edit LOP is starting its own new layer and there's nothing that immediately ties these layers together. This is later resolved by your Configure LOP specifying a consistent Save Path. I explicitly call this out because if you use a Cache LOP for debugging, if you put the Cache LOP *above* the Configure Layer, it won't stitch together the three layers because it can't tell they're the same. It'll just stack them instead, which is legitimate and not a warning/error. If you put the Cache LOP *after* the Configure Layer, however, it will recognise these layers as something we want to stitch together, and then you'll start to get more useful warnings. Starting with...
For the stitching to work at an attribute level, we need the attributes to be consistently named from frame to frame. In your setup, however, the Edit LOPs are each generating transforms with the description "$OS" (i.e., "edit1", "edit2", "edit3"), which means they're not compatible for stitching. What *is* still consistently-named in your setup, however, is the "xformOpOrder" attribute (which lists the order of transformations to apply). It is authored as a default value, and is changing (i.e., when the Switch goes through the first input, the value will be |"transform", "edit1"|, and when it goes through the second input, the value will be |"transform", "edit2"|). This is something the Cache LOP will detect and give a warning for. Changing them to something consistent (e.g., "myEditXform") fixes this. But we're not done...
For the stitching to work at an attribute level, we expect animated data to be generated using time samples. In your setup, however, the transforms generated by the Edit LOP are not time-sampled but, rather, authored as default values. This is something the Cache LOP will detect (i.e., the transforms are animated default values) and give a warning for. Working around this basically means either not using the Edit LOP, or using a Timeshift LOP after the Switch to convert default values into time samples (you can look at the attached hip file to see how it's done).
I think the main takeaways here should be:
1 - Be very careful when using a time-varying Switch LOP ... there are lots of ways it can fail later in the pipeline
2 - Learn to love the Cache LOP as a debugging tool
Hope this helps you (and other readers). I can only apologise that so much technical knowledge is required to make something this conceptually simple work properly.
If you're not interested in the technical details (and I don't blame you if that's the case), I'm attaching a v3 of the scene which should work for you, along with some sticky notes on that changes required to the Edit nodes and the use of a Timeshift LOP.
Okay, now the details.....
The USD ROP, when writing out a multi-frame USD file, needs to stitch together each frame's stage into a single stage containing all the data across all the frames.
A slight aside: the Cache LOP (in "Cache All Frames" mode) does this as well, and is the first debugging tool I usually reach for in cases like yours where you have animation going through a Switch that doesn't survive when writing to disk. The Cache LOP will catch a number of issues (details to follow) and report them as warnings, whereas the USD ROP doesn't (and I'm going to look into why).
For the stitching to work, we only stitch together layers that are "the same". Because you have a Layer Break just before you fan-out and put down the Edit LOPs, each Edit LOP is starting its own new layer and there's nothing that immediately ties these layers together. This is later resolved by your Configure LOP specifying a consistent Save Path. I explicitly call this out because if you use a Cache LOP for debugging, if you put the Cache LOP *above* the Configure Layer, it won't stitch together the three layers because it can't tell they're the same. It'll just stack them instead, which is legitimate and not a warning/error. If you put the Cache LOP *after* the Configure Layer, however, it will recognise these layers as something we want to stitch together, and then you'll start to get more useful warnings. Starting with...
For the stitching to work at an attribute level, we need the attributes to be consistently named from frame to frame. In your setup, however, the Edit LOPs are each generating transforms with the description "$OS" (i.e., "edit1", "edit2", "edit3"), which means they're not compatible for stitching. What *is* still consistently-named in your setup, however, is the "xformOpOrder" attribute (which lists the order of transformations to apply). It is authored as a default value, and is changing (i.e., when the Switch goes through the first input, the value will be |"transform", "edit1"|, and when it goes through the second input, the value will be |"transform", "edit2"|). This is something the Cache LOP will detect and give a warning for. Changing them to something consistent (e.g., "myEditXform") fixes this. But we're not done...
For the stitching to work at an attribute level, we expect animated data to be generated using time samples. In your setup, however, the transforms generated by the Edit LOP are not time-sampled but, rather, authored as default values. This is something the Cache LOP will detect (i.e., the transforms are animated default values) and give a warning for. Working around this basically means either not using the Edit LOP, or using a Timeshift LOP after the Switch to convert default values into time samples (you can look at the attached hip file to see how it's done).
I think the main takeaways here should be:
1 - Be very careful when using a time-varying Switch LOP ... there are lots of ways it can fail later in the pipeline
2 - Learn to love the Cache LOP as a debugging tool
Hope this helps you (and other readers). I can only apologise that so much technical knowledge is required to make something this conceptually simple work properly.
Edited by robp_sidefx - Nov. 16, 2024 04:09:43
- frame_48
- Member
- 16 posts
- Joined: Feb. 2019
- Offline
Thank you! This is incredibly useful to know and makes a lot of sense. It does become incredibly complicated on an actual production scene where artists are using multiple edit nodes, transforms, prunes, etc., all chained together. With this current approach as I understand it you would need to have every single pipe plugged into the switch match in the amount of primitives and operations correct? (since you need to match the name of the transforms)
What we ended up doing on our production shot was to structure our scene graph in a way were we could isolate those different setups that were originally plugged into the switch, and instead we gave them a default visibility value and merged them all together so they are all existing on the scene at the same time. Then we keyframed their visibility with a prune node and added time samples using the timeshift method, before exporting out our USD layer. This seemed to work okay for us but definitely a struggle to figure it out, but know that we understand it I think this would be the way we would approach anything similar in the future.
Thanks again for your time Rob! Super useful explanation.
Best,
Enrique
What we ended up doing on our production shot was to structure our scene graph in a way were we could isolate those different setups that were originally plugged into the switch, and instead we gave them a default visibility value and merged them all together so they are all existing on the scene at the same time. Then we keyframed their visibility with a prune node and added time samples using the timeshift method, before exporting out our USD layer. This seemed to work okay for us but definitely a struggle to figure it out, but know that we understand it I think this would be the way we would approach anything similar in the future.
Thanks again for your time Rob! Super useful explanation.
Best,
Enrique
- robp_sidefx
- Staff
- 501 posts
- Joined: June 2020
- Offline
frame_48
With this current approach as I understand it you would need to have every single pipe plugged into the switch match in the amount of primitives and operations correct?
It depends on what you're trying to do. If you want to have a Switch choose between three different animations for a common object/character, then yes the USD Attributes need to be identically named so as to be compatible for stitching. If you want to have a Switch choose between a sphere or a box or a cube, then no ... Solaris has some handy tech in the Cache and USD ROP to "track primitive existence to set visibility".
- tamte
- Member
- 8785 posts
- Joined: July 2007
- Offline
Would it work if you store all your sub-hierarchies as variants of the common root prim and then animate variant switching?
In my mind it sounds cleaner , especially if they dont have any prims or properties in common
However I dont know if USD allows animating Variant selection, I just assume it does
In my mind it sounds cleaner , especially if they dont have any prims or properties in common
However I dont know if USD allows animating Variant selection, I just assume it does
Tomas Slancik
FX Supervisor
Method Studios, NY
FX Supervisor
Method Studios, NY
- m-cg
- Member
- 15 posts
- Joined: Jan. 2021
- Offline
-
- Quick Links