graphic:python:houdini

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
graphic:python:houdini [2023/01/18 11:11] – [Houdini Pipeline Development] yinggraphic:python:houdini [2024/03/22 06:37] (current) – [HDA Operation (Houdini Digital Asset)] ying
Line 69: Line 69:
             print(str(node) + " description: " + d.description())             print(str(node) + " description: " + d.description())
             print(str(node) + " comment: " + d.comment())             print(str(node) + " comment: " + d.comment())
-            print(str(node) + "path: " + node.type().definition().libraryFilePath())+            print(str(node) + " path: " + node.type().definition().libraryFilePath())
     else:     else:
         print("Selected node is not a HDA")         print("Selected node is not a HDA")
Line 78: Line 78:
  
   * HDA = 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://www.tokeru.com/cgwiki/index.php?title=HoudiniHDA
   * VHDA = versioned houdini digital asset   * VHDA = versioned houdini digital asset
     * ref: create your own videos https://vimeo.com/458751335     * ref: create your own videos https://vimeo.com/458751335
Line 104: 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
 </code> </code>
 +  * node > definition > all info related
  
 +===== Simple hda operation =====
 +
 +  * lock hda node <code python>result_node.matchCurrentDefinition()</code>
 +  * unlock hda node (same like allow edit of content)<code python>
 +if result_node.isLockedHDA():
 +    result_node.allowEditingOfContents()
 +</code>
 +  * open type property dialog of a hda node <code python>hou.ui.openTypePropertiesDialog(result_node)</code>
 +
 +===== Complex hda operation =====
 +
 +
 +  * 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() )
 +</code>
 +  * 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: " + hda_def.description())
 +print(str(node) + " comment: " + hda_def.comment())
 +# definition operation
 +cur_def.isInstalled()
 +cur_def.save(tmp_filepath, template_node=node)
 +</code>
 +  * 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('\n'.join(loaded_hda_file_list))
 +
 +# hda file load/unload
 +hou.hda.installFile(hda_file_path)
 +hou.hda.uninstallFile(hda_file_path)
 +# hda file reload
 +hou.hda.reloadAllFiles(True)
 +</code>
  
  * check and remove HDA <code python>  * check and remove HDA <code python>
Line 122: Line 185:
     # remove action     # remove action
     # os.remove(cur_path)     # os.remove(cur_path)
 +</code>
 +
 +How create new ... HDA works?
 +
 +  - menu calls <code python>
 +import hou
 +import assettools
 +
 +node = kwargs["node"] # it get node from menu click action
 +assettools.createNewVHDAFromSubnet(node)
 +</code>
 +  - assettools.py has function createNewVHDAFromSubnet(), it basically create the dialog
 +  - dialog VHDASaveAsDialog() class show up, the Create button do the node publish
 +    - setMembersFromUI
 +    - namespace_author, namespace_branch, major_version, minor_version = self.getCorrectNamespacesAndVersion()
 +    - library_file = self.getCorrectLibraryFile()
 +    - tablabel = constructVHDALabel(self.tablabel, self.namespace_branch if self.display_branch_in_label_enable else None)
 +    - library_file_path = os.path.join(hou.text.expandString(self.library_dir), library_file)
 +    - vhda_typename = constructVHDATypeName(namespace_author, namespace_branch, self.type_name, major_version, minor_version)
 +    - continue: alert deals with lib path file contains multi- definition
 +    - new asset <code python>
 +createVHDA(node,
 +   namespace_author,
 +   namespace_branch,
 +   self.type_name,
 +   major_version,
 +   minor_version,
 +   tablabel,
 +   self.tabmenu_entry,
 +   self.library_dir,
 +   library_file)
 +</code>
 +    - version up case (a versioned copy of an existing): <code python>
 +copyToVHDAFile(node,
 +   namespace_author,
 +   namespace_branch,
 +   self.type_name,
 +   major_version,
 +   minor_version,
 +   tablabel,
 +   self.tabmenu_entry,
 +   self.library_dir,
 +   library_file)
 +</code>
 +  - details of VHDA function (from assettolls.py) <code python>
 +  def createVHDA(node, namespace_author, namespace_branch, name, major, minor, label, tabmenu, savedir, savefile=None):
 +    hda_name  = constructVHDATypeName(namespace_author, namespace_branch,name,major,minor)
 +    hda_label = label
 +    hda_filename = savefile if savefile else constructVHDAFileName(namespace_author, namespace_branch,name,major,minor)
 +    hda_savedir = savedir
 +    hda_filepath = os.path.join(hda_savedir, hda_filename) if hda_savedir != "Embedded" else "Embedded"
 +
 +    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,connection.inputIndex())
 +        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 == "Embedded",
 +        ignore_external_references=True,
 +    )
 +
 +    vhda_node.setName(name, unique_name=True)
 +    vhda_def = vhda_node.type().definition()
 +
 +    # Update and save new HDA
 +    vhda_options = vhda_def.options()
 +    vhda_options.setSaveInitialParmsAndContents(True)
 +    #vhda_options.setSaveSpareParms(True) ####### TO-DO
 +
 +    vhda_def.setOptions(vhda_options)
 +    '''
 +    setVHDASection(vhda_def, False if namespace_author == "" else True,
 +                             False if namespace_branch == "" else True)
 +    '''
 +    setToolSubmenu(vhda_def, tabmenu)
 +
 +    vhda_def.save(hda_filepath, vhda_node, vhda_options)
 +    hou.hda.installFile(hda_filepath)
 +    hou.hda.reloadAllFiles(True)
 +  
 +</code>
 +  - copyToVHDAFile <code python>
 +def copyToVHDAFile(node, namespace_author, namespace_branch, name, major, minor, label, tabmenu, savedir, savefile=None):
 +    hda_name  = constructVHDATypeName(namespace_author, namespace_branch,name,major,minor)
 +    hda_label = label
 +    hda_filename = savefile if savefile else constructVHDAFileName(namespace_author, namespace_branch,name,major,minor)
 +    hda_savedir = savedir
 +    hda_filepath = os.path.join(hda_savedir, hda_filename) if hda_savedir != "Embedded" else "Embedded"
 +    tmp_filepath = os.path.join(hou.text.expandString("$HOUDINI_TEMP_DIR"),"tmphda.hda")
 +
 +    # 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, template_node=node)
 +
 +    created_definition = hou.hda.definitionsInFile(tmp_filepath)[0]
 +    # Sets the tabmenu location only if it differs from the original
 +    if tabmenu:
 +        setToolSubmenu(created_definition, tabmenu)
 +
 +    created_definition.copyToHDAFile(hda_filepath,hda_name,hda_label)
 +
 +    os.remove(tmp_filepath)
 +    hou.hda.installFile(hda_filepath)
 +    hou.hda.reloadAllFiles(True)
 +    node.changeNodeType(hda_name)  
 </code> </code>
 ====== Tutorial ====== ====== Tutorial ======
  • graphic/python/houdini.1674040280.txt.gz
  • Last modified: 2023/01/18 11:11
  • by ying