Jump to content
Sign in to follow this  

Python event type callback for toggle in multiparm to set other node parm

Recommended Posts

A python newbie here...

I'm working on a small script to make a certain workflow of swapping operator paths for filters a bit less clunky in the context of rendering (with Renderman in this case).

The idea:
1. Click a button (New Filter) to create a new filter node in the shop context - I got this working.

2. That will add a multiparm toggle+operator path. Set the operator path to the newly created filter. - Also done and working.

3. Use toggles to set (and swap) Display Filter operator path parm on the ROP node (ris1) - Far from working :)


I suspect this will have to do with ParmTupleChanged events? and here things become very fuzzy... how do I match the toggle to the operator path to evaluate the correct parm (Filter 1/2/3...)? From a tupple? I guess I need to def a function for that.

But how do I prevent more tan 1 toggle be on at a time... I'm totally stuck.


I hope that makes sence and if anyone could point me in the right direction, that'd be awesome!



Edited by haki

Share this post

Link to post
Share on other sites

Instead of having a checkbox for each filter, you could have a menu like parameter, with a script that lists your multiparm value, thus you will avoid messing around with checkboxes and which of them wins.

As to the rest of your question, there are 2 common models of scripting in Houdini. I call them pull and push models.

In a push model, you hook a callback on a parameter and that callback is pushing values to other Houdini nodes. The main shortcoming of this model is not being able to set parameter values in locked assets. It also makes it hard to debug complex setups(especially not yours) when you have no idea where a parameter value came from.

In the pull model, you hook an expression on the parameter and it does the job. No problems in locked assets and no need to guess the origin of the value in it. The downside is that users won't be able to edit these parameters obviously.

In your case, if the relationship between your CONTROLS and ris1 nodes is deterministic(e.g they know about each other) choose either to push to ris1 from a callback on a menu parameter on the CONTROLS or pull the value from an expression on ris1. Whatever fits better.

Good luck.

Share this post

Link to post
Share on other sites

Ok, I think the push and pull terms are starting to make me see the bigger pucture. Thanks!!

I'd say the node ralationship is non deterministic as the ris1 has no clue about my CONTROLS at all. And it never will as its HDA is not to be messed with. (Btw I've no intention to package this little null (CONTROLS) into an HDA and I've just realized the Null ROP is in fact an HDA itself.)

As for the menu like parm, i hope i'm not getting this totally wrong:
1. Click a button to create a node

2. Set above node's op path in the multiparm string field (at this point i'm starting to think I may even get away without multiparm if I list the children of shop/risnet and get the filters directly into the menu parm (3))

3. Populate menu parameter with new path (or rather, all paths) from multiparm and push selected to ris1 (4.)


Alright. Scripting time.

Edited by haki

Share this post

Link to post
Share on other sites

Ok, getting there:

(A) and (B), still making my mind between the two. Lists of strings:


node = kwargs["node"]
multi_parm = node.parm("filters")
instances = multi_parm.multiParmInstances()

menu = []
for p in range(len(instances)):
    token = str(p);
    value = "Filter {}".format(p+1)

return menu

returns: ['0', 'Filter 1', '1', 'Filter 2', '2', 'Filter 3', '3', 'Filter 4', '4', 'Filter 5']

There's something a bit confusing here: What would I be calling for to get the multiparm instance corresponding to the currently selected token? Or is that just my flawed logic: Current token -> Corresponding multiparm instance - > Push string to other node


menu = []
token = -1
for filter in instances:
    token += 1
    value = filter.eval()
return menu

returns: ['0', '/shop/risnet1/pxrgradedisplayfilter27', '1', '/shop/risnet1/pxrgradedisplayfilter28', '2', '/shop/risnet1/pxrgradedisplayfilter29', '3', '/shop/risnet1/pxrgradedisplayfilter30', '4', '/shop/risnet1/pxrgradedisplayfilter31']

This one seems a bit less confusing. After all the string value I need to push to the other node is right there...i can see it. And then the documentation:

def get_selected_token(parm):
    # Read which item is currently selected
    selected = parm.eval()

    # Get the list of menu tokens from the parameter template
    tokens = parm.parmTemplate().menuItems()

    # Return the token corresponding to the selected item
    return tokens[selected]

Which gets me: 'tuple index out of range' for the dropdown menu parm. (selected = parm.eval() returns the correct token, indeed)




I think I got it: evaluate the button strip/dropdown menu and use the token as the index for .multiParmInstances() evaluated as a string.



If there were say, not 1 but 2 "Add Filter" buttons, is there a way, inside the Script New Filter, to know which button was clicked?

Pushin on. It seems there may be some benefits of turning this into a digital asset and using a python module... I might be tottally ignorant here, but it seems to me functions from a python module make more sense..

Edited by haki
  • Like 1

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this