Updating object parameters via python script for each frame?

   5314   5   0
User Avatar
Member
13 posts
Joined: May 2018
Offline
I want to map each frame of an animation to a specific time-stamp driven by a python script. I constructed a partially working scene from items gleaned in other forum posts and the documentation.

The python script, a node in the /obj level, has the routine Frame2ClockTime which calls hou.frame() and builds a clock string from the frame number. The output string ‘clock’ is then written to the font object. Here's part of the code in the script node ‘/obj/Update_Timestamp’.

clock = Frame2ClockTime(year,month,day,hour,minute,seconds)
# update timestamp object text
hou.node(“/obj/TimeStamp/font1”).parm(“text”).set(clock)

The info box shows the node is Time Dependent.

If I scrub through the frames in Scene View, the timestamp updates correctly.

But if I launch a mantra render, either direct to disk or in background, the timestamp does not update at all, but retains its last value.

I'm probably missing some simple setting, but have not found it.

Suggestions?
Thanks,
Tom
User Avatar
Member
13 posts
Joined: May 2018
Offline
Update: Re-reading the description for the Python Script object node: “The Python Script object allows contained geometries to be altered via python script.”

So I tried moving the font object inside the Update_Timestamp node. This required a minor fix, changing

hou.node(“/obj/TimeStamp/font1”).parm(“text”).set(clock)

to

hou.parm(“/obj/Update_Timestamp/font1/text”).set(clock)

but the results are unchanged. The timestamp updates fine when scrubbing in the Scene View, but doesn't update when rendering.

Tom
User Avatar
Member
10 posts
Joined: April 2016
Offline
I have a very similar problem.
I have a lot of file nodes which I polyReduce and bake textures from with the gamedev simple bake.
I find and set the output paths with python every frame but it doesn't update when rendering!

I've tried both the python sop and object node.
It's at the point where I'm doubting my sanity…

hope there's an answer out there. thanks!
User Avatar
Member
7759 posts
Joined: Sept. 2011
Offline
The solution to this is expressions. Expressions exist on parameters for this very purpose, to have the value depend on other values such as the current frame. ‘Pushing’ values using the cook function of a python object is very non-Houdini, and won't work if that object is not involved in the cook chain, such as when rendering. To properly push values on frame change, one would need to hook into an ‘on frame changed’ callback, which I'm not sure exists. Using expressions is more reliable as they will always be evaluated if time dependent.
User Avatar
Member
10 posts
Joined: April 2016
Offline
Thanks for the answer!
I did have the feeling I was mangling houdini workflow a bit.

But it just seems to me that doing a lot of parameter expressions would just scatter the code into a lot of very long single-line python. Besides the parameter editor (ctrl+E) doesn't have code highlighting

This is my network.

The switch node has an expression on it, changing input with every frame.

Right now i have this in the python1 sop
import customUtils as cstm
reload(cstm)

Bakery  = hou.node('/obj/RawScansBakery')
Switch  = Bakery.node('Switch')

BakerParm   = Bakery.node('Baker').parm('base_path')
FbxerParm   = Bakery.node('Baker').parm('fbx_path')
TexerParm   = Bakery.node('Texer').parm('basecolor_texture_1')

SwitchInput = Switch.inputs()[ Switch.parm('input').eval() ]
curFileNode = cstm.getAncestorType(SwitchInput, 'file')
curFilePath = curFileNode.parm('file').eval()

BakerParm.set(  curFilePath.replace('raw.obj','$(CHANNEL).tga')  )
FbxerParm.set(  curFilePath.replace('raw.obj','retopo.fbx')  )
TexerParm.set(  curFilePath.replace('.obj','.png')  )

This basically gets the current switch input and gets to the file sop and reads the input path.
Then it sets the paths for the Simple Bake SOP and ROP_fbx nodes below.

Would I really have to write all that in every parameter?
Else I could make a custom function, but where?
Not sure which context I could declare anything in and have it update on every frame like the expressions?

thanks!
Edited by bastianlstrube - Feb. 21, 2019 09:47:42

Attachments:
switchloaded.PNG (38.1 KB)

User Avatar
Member
10 posts
Joined: April 2016
Offline
Think I found the more Houdini-esque way to do it.

I moved the python code into a function in the source editor, so writing to the hou.session module:
def pather(outputType):
    
    Bakery  = hou.node('/obj/RawScansBakery')
    Switch  = Bakery.node('Switch')
    SwitchInput = Switch.inputs()[ Switch.parm('input').eval() ]
    curFileNode = had.getAncestorType(SwitchInput, 'file')
    curFilePath = curFileNode.parm('file').eval()
    
    pathDict = {
        'fbx':   curFilePath.replace('raw.obj','retopo.fbx'),
        'tga':   curFilePath.replace('raw.obj','$(CHANNEL).tga'),
        'png':   curFilePath.replace('.obj','.png'),
    }
    return pathDict[outputType]

and then in the parameters for the ROP_fbx and texture baker added this little snippet:



Seems to work. Thanks for the pointer to expressions!
Edited by bastianlstrube - Feb. 22, 2019 04:17:53

Attachments:
parameterExpressionSolution.PNG (73.1 KB)

  • Quick Links