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
Last revisionBoth sides next revision
graphic:python:houdini [2022/11/21 07:52] – [HDA Operation (Houdini Digital Asset)] yinggraphic: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 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 62: 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())
     else:     else:
         print("Selected node is not a HDA")         print("Selected node is not a HDA")
Line 68: Line 76:
 </code> </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>
     * related hda menu code <code python>     * related hda menu code <code python>
 #menu id: opmenu.create_hda #menu id: opmenu.create_hda
- 
 kwargs["node"].canCreateDigitalAsset() kwargs["node"].canCreateDigitalAsset()
- 
  
 #menu id: opmenu.vhda_options_create #menu id: opmenu.vhda_options_create
- 
 import hou import hou
 import assettools import assettools
- 
 node = kwargs["node"] node = kwargs["node"]
 if assettools.isSubnet(node): if assettools.isSubnet(node):
Line 88: Line 108:
  
 #menu id: opmenu.vhda_create #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
 +  * 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 hou
 import assettools import assettools
  
-node = kwargs["node"]+node = kwargs["node"# it get node from menu click action
 assettools.createNewVHDAFromSubnet(node) assettools.createNewVHDAFromSubnet(node)
 </code> </code>
-  * Houdini python API library path: <code>Houdini_VERSION\houdini\python3.7libs\</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.txt
  • Last modified: 2024/03/22 06:37
  • by ying