Table of Contents

Houdini Shortcut

Node View
show node view mini map O
show node property corner panel P
layout selected nicely shift + L
align selected hold A and drag align direction
duplicate selected alt+drag selected
cut connection hold Y and drag line to cut
netbox nodes (like node group in nuke) shift+O
subnet nodes
(like a tiny world
with inputs+outputs to outside)
shift+C
node color palette C
create note shift+P
node group manager (like display layer in maya) shift+Z
move connection line alt+click drag line middle

Houdini Pipeline Development

HDA Operation (Houdini Digital Asset)

Simple hda operation

Complex hda operation

* check and remove HDA

# 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)

How create new … HDA works?

  1. menu calls
    import hou
    import assettools
     
    node = kwargs["node"] # it get node from menu click action
    assettools.createNewVHDAFromSubnet(node)
  2. assettools.py has function createNewVHDAFromSubnet(), it basically create the dialog
  3. dialog VHDASaveAsDialog() class show up, the Create button do the node publish
    1. setMembersFromUI
    2. namespace_author, namespace_branch, major_version, minor_version = self.getCorrectNamespacesAndVersion()
    3. library_file = self.getCorrectLibraryFile()
    4. tablabel = constructVHDALabel(self.tablabel, self.namespace_branch if self.display_branch_in_label_enable else None)
    5. library_file_path = os.path.join(hou.text.expandString(self.library_dir), library_file)
    6. vhda_typename = constructVHDATypeName(namespace_author, namespace_branch, self.type_name, major_version, minor_version)
    7. continue: alert deals with lib path file contains multi- definition
    8. new asset
      createVHDA(node,
         namespace_author,
         namespace_branch,
         self.type_name,
         major_version,
         minor_version,
         tablabel,
         self.tabmenu_entry,
         self.library_dir,
         library_file)
    9. version up case (a versioned copy of an existing):
      copyToVHDAFile(node,
         namespace_author,
         namespace_branch,
         self.type_name,
         major_version,
         minor_version,
         tablabel,
         self.tabmenu_entry,
         self.library_dir,
         library_file)
  4. details of VHDA function (from assettolls.py)
      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)
     
  5. copyToVHDAFile
    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)  

Tutorial