Hi everyone,
lately I have been testing solutions to build a python tool that allows me to quickly save node networks to a python file and being able to choose presets on disk and execute them, similar to dragging node constellations into the Shelf.
So far I it worked pretty good by using the hou.Node.asCode() method, but this quickly breaks down when using Attribute Vops
As far as I understand, by dragging nodes into the shelf, it generates some hscript code (Shown in the picture below).
My question: Is there a way to generate this hscript code with python, so kind of what dragging nodes into the shelf does, but with code myself, so I can use it to save snippets to disk myself?
Thanks in advance!
Node networks to hscript / Python
1603 7 4- JoshRizzo
- Member
- 9 posts
- Joined: Dec. 2018
- Offline
- mrCatfish
- Member
- 731 posts
- Joined: Dec. 2006
- Offline
- JoshRizzo
- Member
- 9 posts
- Joined: Dec. 2018
- Offline
mrCatfishYes, exactly! Thanks
hou.hscript("opscript -b -r -s /path/to/node")
Does that also keep intact node connections like dragging into the shelf does?? (If I run over multiple nodes) Or can I do something like this
hs_code = hou.hscript("opscript -b -r -s /path/to/node /path/to/node2 /path/to/node3")
- cncverkstad
- Member
- 117 posts
- Joined: Aug. 2017
- Offline
Maybe can be useful for someone , endless possibility for speed and creativity .
#Save_Nodes.py import hou # cpio dirPath = "DIRECTORY" def SaveTemplate(name): sel = hou.selectedNodes() path = sel[0].path() nodeCategoryName = sel[0].type().category().name() pathSplit = path.split("/") pathSplit.pop(-1) getRootPath = "/".join(pathSplit) rootName = getRootPath[1:].replace("/","_") contextnode = hou.node(getRootPath) filename = "{}/{}_{}".format(dirPath, nodeCategoryName, name + ".cpio") contextnode.saveItemsToFile(sel, filename, save_hda_fallbacks = False) hou.ui.displayMessage("Success!\n" + "Save File: "+filename) print("Save File: "+filename) Dialog = hou.ui.readInput(message ="Save Select Nodes?\n",title = "Save Template",severity=hou.severityType.Message,buttons=["Save","Cancel"]) if Dialog[0]==0: SaveTemplate(Dialog[1])
# Import_Nodes.py import hou import os # cpio dirPath = "DIRECTORY" files = os.listdir(dirPath) fileList = [f for f in files if os.path.isfile(os.path.join(dirPath, f))] def ImportTemplate(filename): desktop = hou.ui.curDesktop() pane = desktop.paneTabOfType(hou.paneTabType.NetworkEditor) current_context = pane.pwd().path() hou.clearAllSelected() contextnode = hou.node(current_context) nodes = contextnode.loadItemsFromFile(filename, ignore_load_warnings=False) sel = hou.selectedNodes() firstNodePos = sel[0].position() for node in sel: node.setPosition( node.position() + hou.ui.paneTabOfType(hou.paneTabType.NetworkEditor).visibleBounds().center() - firstNodePos ) Dialog = hou.ui.selectFromList(fileList, message='Select Import File') if len(Dialog)!=0: for i in Dialog: ImportTemplate("{}/{}".format(dirPath, fileList[i]))
Conservation of Momentum
- JoshRizzo
- Member
- 9 posts
- Joined: Dec. 2018
- Offline
Thanks both!
I found a way for myself in case anyone is interested.
Of course I need to work on creating an UI for this, custom file naming and loading etc.
I'm saving a dictionary at the start of the text file for safe renaming like this:
Preset Saving:
Preset Loading:
I found a way for myself in case anyone is interested.
Of course I need to work on creating an UI for this, custom file naming and loading etc.
I'm saving a dictionary at the start of the text file for safe renaming like this:
[{'temp_name': 'CPPS_NODE0', 'name': 'attribvop1'}, {'temp_name': 'CPPS_NODE1', 'name': 'attribvop2'}, {'temp_name': 'CPPS_NODE2', 'name': 'attribvop4'}, {'temp_name': 'CPPS_NODE3', 'name': 'attribvop3'}]
import hou nodes = hou.selectedNodes() names = [] for n in nodes: names.append(n.name()) curP = nodes[0].parent() # Create duplicates new_nodes = hou.copyNodesTo(nodes, curP) definition = [] # Make dictionary and rename nodes to temporary names for num, new in enumerate(new_nodes): new_def = {} old_name = names[num] new.setName("CPPS_NODE{}".format(num)) new_def["temp_name"] = "CPPS_NODE{}".format(num) new_def["name"] = old_name definition.append(new_def) definition_str = str(definition) print(definition_str) # Create multiuple node string for hscript command node_string = "" for node in new_nodes: path = node.path() node_string += " " + path hs = hou.hscript("opscript -b -r -s{}".format(node_string)) # Delete temp nodes for d in new_nodes: d.destroy() # Add dictionary to top line final_output = definition_str + "\n \n" for h in hs: final_output += h final_output += " " file = open("C:/Users/Joshi/Desktop/Preset-Save/test.txt","w") file.write(final_output) file.close()
Preset Loading:
import sys import toolutils import hou import json h_extra_args = '' pane = toolutils.activePane(kwargs) if not isinstance(pane, hou.NetworkEditor): pane = hou.ui.paneTabOfType(hou.paneTabType.NetworkEditor) if pane is None: hou.ui.displayMessage( 'Cannot create node: cannot find any network pane') sys.exit(0) pane_node = pane.pwd() child_type = pane_node.childTypeCategory().nodeTypes() if 'attribvop' not in child_type: hou.ui.displayMessage( 'Cannot create node: incompatible pane network type') sys.exit(0) pane_node.setSelected(False, True) h_path = pane_node.path() h_preamble = 'set arg1 = "' + h_path + '"\n' h_cmd = "" with open("C:/Users/Joshi/Desktop/Preset-Save/test.txt","r") as file: temp = file.read() # Filter first line to be json dictionary dict_str = "" for num, l in enumerate(temp.splitlines()): if num == 0: dict_str = l.replace("'",'"') else: if "opcf " in l: l = "opcf $arg1" h_cmd += l + "\n" d = json.loads(dict_str) hou.hscript(h_preamble + h_extra_args + h_cmd) # Rename nodes to fit name from dictionary for item in d: temp_name = item["temp_name"] name = item["name"] node = hou.node("{}/{}".format(pane_node.path(),temp_name)) node.setName(name,True) node.setSelected(True)
- EJaworenko
- Member
- 52 posts
- Joined: June 2017
- Offline
- JoshRizzo
- Member
- 9 posts
- Joined: Dec. 2018
- Offline
EJaworenko
This doesn't happen to also save out parameters does it? I've made similar scripts but this is a good bit more elegant.
I discovered a much cleaner way to generate these files, without any hscript
For saving:
contextnode = hou.node(getRootPath) contextnode.saveItemsToFile(nodes, filename, save_hda_fallbacks = False)
And for loading:
contextnode = hou.node(getRootPath) contextnode.loadItemsFromFile(file_load, ignore_load_warnings=False)
This is muuuch cleaner and retains all node connections, subnets, parameters and works in any context.
- EJaworenko
- Member
- 52 posts
- Joined: June 2017
- Offline
JoshRizzo
I discovered a much cleaner way to generate these files, without any hscript
For saving:contextnode = hou.node(getRootPath) contextnode.saveItemsToFile(nodes, filename, save_hda_fallbacks = False)
And for loading:contextnode = hou.node(getRootPath) contextnode.loadItemsFromFile(file_load, ignore_load_warnings=False)
This is muuuch cleaner and retains all node connections, subnets, parameters and works in any context.
Damn! Its almost like they designed a couple functions for this specifically. I'll have to test it out, thanks!
Houdini TD, I focus on tools for procedural asset creation.
www.jaworenko.design
www.jaworenko.design
-
- Quick Links