Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revisionLast revisionBoth sides next revision | ||
graphic:python:houdini [2022/11/21 07:59] – [Houdini Pipeline Development] ying | graphic:python:houdini [2023/05/31 09:08] – [HDA Operation (Houdini Digital Asset)] ying | ||
---|---|---|---|
Line 2: | Line 2: | ||
| Node View || | | Node View || | ||
+ | | show node view mini map | O | | ||
+ | | show node property corner panel | P | | ||
| layout selected nicely | shift + L | | | layout selected nicely | shift + L | | ||
| align selected | hold A and drag align direction | | | align selected | hold A and drag align direction | | ||
Line 67: | Line 69: | ||
print(str(node) + " description: | print(str(node) + " description: | ||
print(str(node) + " comment: " + d.comment()) | print(str(node) + " comment: " + d.comment()) | ||
+ | print(str(node) + " path: " + node.type().definition().libraryFilePath()) | ||
else: | else: | ||
print(" | print(" | ||
Line 73: | Line 76: | ||
</ | </ | ||
====== HDA Operation (Houdini Digital Asset) ====== | ====== HDA Operation (Houdini Digital Asset) ====== | ||
+ | |||
+ | * HDA = houdini digital asset | ||
+ | * a set of node network functions as a core process | ||
+ | * like model asset but instead of geo, it can be anything, like shading network, rig network or anything process. | ||
+ | * once you add hda path into your houdini env, you can load it from tab menu like rest built-in hda asset (like nuke gizmo) | ||
+ | * each hda is like a programming class, it has its unique type name like class name, all node of its class are instance of the node definition (its original content network) | ||
+ | * once a instance of hda in the scene, it is like maya model reference, you can unlock and make additional changes (**Allow editing of contents**), | ||
+ | * you can save the changes back into hda files (**Save node type**), or just keep changes in the scene | ||
+ | * to revert back to original state, just select node, use (**Match current definition** cmd) | ||
+ | * hda file can contain many hda assets, but recommed one asset for one hda file | ||
+ | * hda asset can be inside houdini scene file, as Embedded instead of on a path file | ||
+ | * nested hda need to be manually updated inside | ||
+ | * ref: | ||
+ | * https:// | ||
+ | * VHDA = versioned houdini digital asset | ||
+ | * ref: create your own videos https:// | ||
* Houdini default menu source code: < | * Houdini default menu source code: < | ||
Line 97: | Line 116: | ||
#hda related files | #hda related files | ||
assettools.py | assettools.py | ||
+ | C:\Program Files\Side Effects Software\Houdini X\houdini\python3.7libs\assettools.py | ||
</ | </ | ||
+ | * node > definition > all info related | ||
+ | * node info <code python> | ||
+ | # node | ||
+ | if len(hou.selectedNodes()) == 1: | ||
+ | node = hou.selectedNodes()[0] | ||
+ | # node info | ||
+ | print(str(node) + " name: " + node.type().name() ) | ||
+ | print(str(node) + " locked: " + node.isLockedHDA() ) | ||
+ | </ | ||
+ | * definition <code python> | ||
+ | # definition | ||
+ | if node.type().definition() is not None: | ||
+ | hda_def = node.type().definition() | ||
+ | |||
+ | # definition info | ||
+ | print(str(node) + " path: " + hda_def.libraryFilePath() ) | ||
+ | print(str(node) + " version: " + hda_def.version()) | ||
+ | print(str(node) + " description: | ||
+ | print(str(node) + " comment: " + hda_def.comment()) | ||
+ | # definition operation | ||
+ | cur_def.isInstalled() | ||
+ | cur_def.save(tmp_filepath, | ||
+ | </ | ||
+ | * hda file <code python> | ||
+ | # hda file | ||
+ | hda_file_path = hda_def.libraryFilePath() | ||
+ | definition_list = hou.hda.definitionsInFile(hda_file_path) | ||
+ | |||
+ | # check hda file list loaded in memory | ||
+ | loaded_hda_file_list= hou.hda.loadedFiles() | ||
+ | print(' | ||
+ | |||
+ | # hda file load/unload | ||
+ | hou.hda.installFile(hda_file_path) | ||
+ | hou.hda.uninstallFile(hda_file_path) | ||
+ | # hda file reload | ||
+ | hou.hda.reloadAllFiles(True) | ||
+ | </ | ||
+ | |||
+ | * check and remove HDA <code python> | ||
+ | # hda_file_path: | ||
+ | cur_path = hda_file_path | ||
+ | if os.path.isfile(cur_path): | ||
+ | # uninstall for safe | ||
+ | definitions = hou.hda.definitionsInFile(cur_path) | ||
+ | is_installed = 0 | ||
+ | for d in definitions: | ||
+ | if d.isInstalled(): | ||
+ | is_installed = 1 | ||
+ | if is_installed: | ||
+ | # Uninstall the HDA | ||
+ | hou.hda.uninstallFile(cur_path) | ||
+ | # remove action | ||
+ | # os.remove(cur_path) | ||
+ | </ | ||
+ | |||
+ | How create new ... HDA works? | ||
+ | |||
+ | - menu calls <code python> | ||
+ | import hou | ||
+ | import assettools | ||
+ | |||
+ | node = kwargs[" | ||
+ | assettools.createNewVHDAFromSubnet(node) | ||
+ | </ | ||
+ | - assettools.py has function createNewVHDAFromSubnet(), | ||
+ | - dialog VHDASaveAsDialog() class show up, the Create button do the node publish | ||
+ | - setMembersFromUI | ||
+ | - namespace_author, | ||
+ | - library_file = self.getCorrectLibraryFile() | ||
+ | - tablabel = constructVHDALabel(self.tablabel, | ||
+ | - library_file_path = os.path.join(hou.text.expandString(self.library_dir), | ||
+ | - vhda_typename = constructVHDATypeName(namespace_author, | ||
+ | - continue: alert deals with lib path file contains multi- definition | ||
+ | - new asset <code python> | ||
+ | createVHDA(node, | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | </ | ||
+ | - version up case (a versioned copy of an existing): <code python> | ||
+ | copyToVHDAFile(node, | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | </ | ||
+ | - details of VHDA function (from assettolls.py) <code python> | ||
+ | def createVHDA(node, | ||
+ | hda_name | ||
+ | hda_label = label | ||
+ | hda_filename = savefile if savefile else constructVHDAFileName(namespace_author, | ||
+ | hda_savedir = savedir | ||
+ | hda_filepath = os.path.join(hda_savedir, | ||
+ | |||
+ | max_num_inputs = 0 | ||
+ | |||
+ | # If there are inputs to the node, find the largest index of the input connections and use it as the max_num_inputs | ||
+ | # This will preserve the inputs at the right indexes | ||
+ | if len(node.inputs()) > 0: | ||
+ | for connection in node.inputConnections(): | ||
+ | max_num_inputs = max(max_num_inputs, | ||
+ | max_num_inputs = max_num_inputs + 1 | ||
+ | |||
+ | vhda_node = node.createDigitalAsset( | ||
+ | name = hda_name, | ||
+ | hda_file_name = hda_filepath, | ||
+ | description = hda_label, | ||
+ | min_num_inputs = 0, | ||
+ | max_num_inputs = max_num_inputs, | ||
+ | save_as_embedded = hda_savedir == " | ||
+ | ignore_external_references=True, | ||
+ | ) | ||
+ | |||
+ | vhda_node.setName(name, | ||
+ | vhda_def = vhda_node.type().definition() | ||
+ | |||
+ | # Update and save new HDA | ||
+ | vhda_options = vhda_def.options() | ||
+ | vhda_options.setSaveInitialParmsAndContents(True) | ||
+ | # | ||
+ | |||
+ | vhda_def.setOptions(vhda_options) | ||
+ | ''' | ||
+ | setVHDASection(vhda_def, | ||
+ | False if namespace_branch == "" | ||
+ | ''' | ||
+ | setToolSubmenu(vhda_def, | ||
+ | |||
+ | vhda_def.save(hda_filepath, | ||
+ | hou.hda.installFile(hda_filepath) | ||
+ | hou.hda.reloadAllFiles(True) | ||
+ | | ||
+ | </ | ||
+ | - copyToVHDAFile <code python> | ||
+ | def copyToVHDAFile(node, | ||
+ | hda_name | ||
+ | hda_label = label | ||
+ | hda_filename = savefile if savefile else constructVHDAFileName(namespace_author, | ||
+ | hda_savedir = savedir | ||
+ | hda_filepath = os.path.join(hda_savedir, | ||
+ | tmp_filepath = os.path.join(hou.text.expandString(" | ||
+ | |||
+ | # Update and save new HDA | ||
+ | vhda_def = node.type().definition() | ||
+ | # vhda_options = vhda_def.options() | ||
+ | # vhda_options.setSaveInitialParmsAndContents(True) | ||
+ | # vhda_options.setSaveSpareParms(True) ####### TO-DO | ||
+ | |||
+ | vhda_def.save(tmp_filepath, | ||
+ | |||
+ | created_definition = hou.hda.definitionsInFile(tmp_filepath)[0] | ||
+ | # Sets the tabmenu location only if it differs from the original | ||
+ | if tabmenu: | ||
+ | setToolSubmenu(created_definition, | ||
+ | |||
+ | created_definition.copyToHDAFile(hda_filepath, | ||
+ | |||
+ | os.remove(tmp_filepath) | ||
+ | hou.hda.installFile(hda_filepath) | ||
+ | hou.hda.reloadAllFiles(True) | ||
+ | node.changeNodeType(hda_name) | ||
+ | </ | ||
+ | ====== Tutorial ====== | ||
+ | |||
+ | * [Houdini official] Houdini Digital Assets | 1. Introduction to HDAs (2021) | ||
+ | * https:// | ||
+ | |||
+ | |||