Referencing primvars in output path

   2481   9   3
User Avatar
Member
33 posts
Joined: March 2017
Offline
How would we go about using usd primvars in a string parameter?
For example, having a usd prim with attributes like "shot" and "version" and using those to drive the output file?

The only approach I can find is to use the usd python modules, but I was hoping there's a simpler method like hscript, vexpression or "@primvar".
User Avatar
Member
33 posts
Joined: March 2017
Offline
Here's my findings on this in case it helps anyone.

Context options are the way to go. They set variables that can be referenced with the @ syntax.
They can be set manually in the Context Options editor but can also be changed in your node tree.

There are two approaches I've found, each with their own pros and cons.

Edit Context Options LOP
This has a nice interface that allows you to set context options.
Confusingly (at least for me) this will set the context values up the node tree rather than down.
So this node needs to be placed after any node that needs to reference the variables it sets.

Python Script LOP
hou.setContextOption('name', 'value')
This lets you set values that can be referenced globally, so both up and down the node tree (and even in separate disconnected node trees, so be careful).
Important to note that context options set with the python script are persistent, so if you bypass or even delete the python script LOP the context option will still be set. I'm not sure if this is a bug or intended but it's something to be aware of.

For my purposes this time I went with the Python Script LOP as I have structured my network such that the shot variables are set at the top of the netork and need to flow down. I don't really recommend this approach though.
In future I will try reorganising my networks to make them work with the Edit Context Options LOP as that is much more controlled (i.e. the context options are only set for specific nodes in the network and this can even be limited with context options blocks).
Edited by pixelninja - March 30, 2023 19:59:50

Attachments:
context options.jpg (52.8 KB)

User Avatar
Staff
4454 posts
Joined: July 2005
Offline
Please do not use the Python LOP approach. As you point out, using `hou.setContextOption` sets the context option _globally_ (it doesn't "flow" up or down the chain - it makes a persistent change to the state of the hip file, like setting an environment variable with `hou.putenv`). It will affect every LOP node in your whole hip file until you call `hou.setContextOption` again (or change this global value in the UI with the Edit->Context Options dialog).

Now you may say "but it's easy to set this value from my python LOPs". And I say "but only when you _cook_ those python LOPs". So when you open the hip file, the switch is set to "0", and the first python LOP cooks, set the context option, and everything looks great. Change the Switch to "1", and the second Python LOP cooks, changes the context option value, everything recooks with the new context option value and everything looks great. Now change the switch back to "0". The first python LOP isn't "dirty". It doesn't have any parameters that have changed value. So it doesn't cook. It just sends down the (empty) stage it generated the first time it cooked. Because it doesn't cook, its code doesn't run, the context option value doesn't change, and everything continue to show the output of the context option value set by the _second_ python LOP. Everything is bad. And this is just one of several ways in which this approach can (and eventually will) go wrong.

Context options that are meant to be "local" (in the sense that their value is set during LOP node cooking) can _only_ be safely set with an Edit Context Options LOP (or a For Each LOP or USD ROP all of which have the context option control built into them). And "local" context options _only_ flow up the network.

Context options that are "global" should be set and controlled from the UI or via scripts (executed with buttons or other explicit user actions). They should never be set as part of a node cook (well, never say never, but definitely not in this scenario where you're trying to use them as a replacement for an Edit Context Options LOP).
Edited by mtucker - March 30, 2023 21:20:09
User Avatar
Member
33 posts
Joined: March 2017
Offline
You're right. I hadn't noticed it doing that, possibly as I'm not manually rendering. Thanks for the warning.
I'll switch back to pdg variables just to be safe, as that's what I've been using up until now.

Does this mean that the only way to pass a string variable down the node tree is by using primvars and then reading them back with a python expression? Is there no way of @ referencing some kind of data point passed down the tree?

In my case this could all be solved by simply putting the render settings at the top of the node tree, but it feels wrong not to have it next to the render rop for some reason haha.
User Avatar
Staff
4454 posts
Joined: July 2005
Offline
You can send data "down" the network by putting it anywhere you want on the USD stage. We have (or had - I don't know if we still do it) some HDAs that add metadata to the /HoudiniLayerInfo prim at the top of the HDA (based on some expensive computation), then the rest of the nodes in the HDA can just read the value out of the metadata. The loputils.py module even has some methods for doing this: storeParameterValues and fetchParameterValues. Or you can use primvars. Or regular attributes. Or custom prims. Or metadata. Or custom data. No end of ways to attach little bits of "extra" data to a stage that can be read by nodes further down the chain.

But I'm not seeing the connection between what's being discussed here and the question of where in your network your render settings LOP nodes live?
User Avatar
Member
33 posts
Joined: March 2017
Offline
The whole impetus behind the question was that I had a network with a bunch of branches at the top leading down (through a switch) to a single render settings lop and usd render rop, and I was looking for a simple way of sticking an attribute on each branch and then referencing that with an @ variable into the output image on the render settings.

What we've discussed here has shown that the built in system for setting and @ referencing variables (context options) works upwards. Therefore in order for this to work in my case, where the branches are a the top of the node tree, I would need to rearrange things such that the shared render setting node is at the top of the tree, this would then branch out to each branch (which will set a convext option) then down through the switch and finally the rop. The render setting now being at the top of the tree enables it to pick up the branch specific context option via the selection on the downstream switch node.

Thanks for enumerating all of those methods, but specifically I was looking for one that works with @ referencing (rather than needing to read back the value with python) which I don't think any of those allow right? I did suspect that maybe custom data on the /HoudiniLayerInfo prim might work though... I can also use a python expression to grab data from wherever, however that's less clear than being able to simply say "$HIP/render/`@shot`.$F4.exr" or whatever.

It's all good, thanks so much for your help. It's clear that my current approach is working against the tools and not with them.
User Avatar
Staff
4454 posts
Joined: July 2005
Offline
Thanks for the explanation. That makes sense. These issues of shots and passes, branching and re-merging, are things where the details really matter, and the more examples we see of different approaches the better we will be able to make the tools that support this wide variety of workflows. As you say, there is currently nothing that lets you create information accessible through the "@" syntax.

One approach you might consider would be to have some LOPs at the top that just create completely empty, default render settings/render product prims. Maybe even a sublayer that loads in a basic template from disk. Then your branches can put the output file information in the right spot on these existing prims. You still keep your "real" render settings prim at the bottom of the network, and have it just make edits to the existing prim(s). Then you never have to worry about "transmitting" information from one LOP node to another. Every LOP just authors in-place on the stage. This approach would also let each branch set other render settings that may be specific to that branch, without having to add yet more "@" variables (or their equivalent) to transmit the desired opinions "down" to the render settings LOP.
User Avatar
Member
8622 posts
Joined: July 2007
Offline
I'm also curious how the proposed stage variables [openusd.org] will come into play if implemented
Tomas Slancik
FX Supervisor
Method Studios, NY
User Avatar
Member
33 posts
Joined: March 2017
Offline
Thanks, that sounds like a great solution. I'll give that a go!

Sorry for not being more specific earlier.
I found that for simple seqeuences with little variation between shots it was easier to have a single rop (or multiples if I need separate passes) which I could point a topnet at to batch out all of the shots. The switch being necessary to add any required variation.

I was using pdg_variables initially but I like to avoid them where possible to keep my networks pdg agnostic as it simplifies thing when you want to rerender specific shots manually.
User Avatar
Member
33 posts
Joined: March 2017
Offline
tamte
I'm also curious how the proposed stage variables [openusd.org] will come into play if implemented

That looks incredibly useful. I love the expression functionality proposed too.
  • Quick Links