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 [2022/11/16 08:58] – [Houdini Shortcut] yinggraphic:python:houdini [2024/03/22 06:37] (current) – [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 17: Line 19:
   * ref:   * ref:
     * 5 Ways to Organize your Network in Houdini 17.5 (IndiePixel3D) https://www.youtube.com/watch?v=w8yBoO-qvsk     * 5 Ways to Organize your Network in Houdini 17.5 (IndiePixel3D) https://www.youtube.com/watch?v=w8yBoO-qvsk
 +
 +
 ====== Houdini Pipeline Development ====== ====== Houdini Pipeline Development ======
  
   * Python 3 and built-in PySide2   * Python 3 and built-in PySide2
 +  * houdini has its built-in qt library (PySide2), just import its own <code>
 +from hutil.Qt import QtCore, QtGui, QtWidgets
 +</code>
  
   * houdini lic type check<code python>   * houdini lic type check<code python>
Line 48: Line 55:
  
 </code> </code>
 +  * detect selected hda node info <code python> 
 +import hou 
 +if len(hou.selectedNodes()) == 1: 
 +    node = hou.selectedNodes()[0] 
 +    if node.type().definition() is not None: 
 +        hda_file_path = node.type().definition().libraryFilePath() 
 +        print(hda_file_path) 
 +        definitions = hou.hda.definitionsInFile(hda_file_path) 
 +        print(definitions) 
 +        for d in definitions: 
 +            print(str(node) + " name: " + node.type().name() ) 
 +            print(str(node) + " version: " + d.version()) 
 +            print(str(node) + " description: " + d.description()) 
 +            print(str(node) + " comment: " + d.comment()) 
 +            print(str(node) + " path: " + node.type().definition().libraryFilePath()) 
 +    else: 
 +        print("Selected node is not a HDA"
 +else: 
 +    print("Please select 1 hda node"
 +</code>
 ====== 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://www.tokeru.com/cgwiki/index.php?title=HoudiniHDA
 +  * VHDA = versioned houdini digital asset
 +    * ref: create your own videos https://vimeo.com/458751335
  
   * Houdini default menu source code: <code>Houdini_VERSION\houdini\OPmenu.xml</code>   * Houdini default menu source code: <code>Houdini_VERSION\houdini\OPmenu.xml</code>
-  * Houdini python API library path: <code>Houdini_VERSION\houdini\python3.7libs\</code>+    * related hda menu code <code python> 
 +#menu id: opmenu.create_hda 
 +kwargs["node"].canCreateDigitalAsset() 
 + 
 +#menu id: opmenu.vhda_options_create 
 +import hou 
 +import assettools 
 +node = kwargs["node"
 +if assettools.isSubnet(node): 
 +    return 1 
 +else: 
 +    return 0 
 + 
 +#menu id: opmenu.vhda_create 
 +import hou 
 +import assettools 
 +node = kwargs["node"
 +assettools.createNewVHDAFromSubnet(node) 
 +</code> 
 +  * Houdini python API library path: <code>Houdini_VERSION\houdini\python3.7libs\ 
 +#hda related files 
 +assettools.py 
 +C:\Program Files\Side Effects Software\Houdini X\houdini\python3.7libs\assettools.py 
 +</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> 
 +# hda_file_path: the path of hda file 
 +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) 
 +</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> 
 +====== Tutorial ====== 
 + 
 +  * [Houdini official] Houdini Digital Assets | 1. Introduction to HDAs (2021) 
 +    * https://www.youtube.com/watch?v=ybk8XWBnO4o 
 + 
  
  • graphic/python/houdini.1668589116.txt.gz
  • Last modified: 2022/11/16 08:58
  • by ying