Houdini for TD - HDA & Operators

Note

This article is part of the serie Houdini for TD

Working with HDA

HDA (Houdini Digital Asset), which used to be name OTL (Orbolt Tool Library), are usually tools built to streamline workflows. They allow to wrap up large network into a single node with an artist-friendly interface.

As TD, HDA are one of the main way to provide tools for the Artist to interact with as they can integrate smoothly in their work.

HDA Creation is covered in many tutorial such as SideFX Introduction to Digital Assets.

Note

I invite you to read this article about HDA Best Practice, which provide general recommendation to improve the HDA's quality.

Special HDA

It is most common to create HDA from a subnetwork and click Create Digital Assets... This mechanic is great for creating tools that are based on Houdini nodes, but other types of HDA can be created.

In the Main menu, go in File > New Asset... , a new dialog will open asking you the same basic questions about a name and label for your HDA and where to save it. But you can notice you have the ability to select a different "Definition" type. The most common type of definition is "Subnetwork", but other most useful one could be Python and Output Driver.

Those HDA behavior can be customized by editing the Code Section when editing them.

You might also notice that those nodes cannot be "Unlocked and edit..."

HDA versioning

There is usually two way of versionning your HDA, with both pro and cons.

  • Name the node type to include the version name
  • Use the version only in the file path

In the first case, to change version number, you are required to change the node type of the node by calling:

hou.Node.changeNodeType(new_node_type)

While in the second case, you can update version by marking the definition included in the hda file as preferred:

hou.HDADefinition.setPreferred(True)

The main difference between those two solution, in the first case each node can use a different version, requiring to update each node individually. Whereas in the second case, all nodes will be updated all at once, without the capacity to lock the version on a node specificly.

Embedded HDA

Often overlooked, Embedded HDA can sometime represent a useful alternative to storing files on disk. HDA often tend to be stored internally in the scene when their source file become unavailable. Though, storing an HDA as Embedded can be useful in some cases.

If you are planning to share your file with someone who is not the same network as you or won't have access to all your HDA files, embedding the HDA is a really nice and conveniant way to package your scene.

HDA files when saved, depending on your configuration, should create backup file, though, those changes are only stored when the HDA is being written to disk. In development stages, by storing an HDA in your scene, you can use the scene file save mechanic to create clever backup of your HDA development.

HDA Expanded structure

When you save your HDA, they are by default saved into a binary file which is easy for houdini to open. Though, if the HDA is part of a package it can be really hard to track changes on it. An option is to expand the HDA using the following commands:

# To expand an HDA into a VCS friendly folder
hotl -t expanded.hda original.hda

# To collapse a VCS expanded HDA into a binary HDA
hotl -l expanded.hda collapsed.hda

Once expanded a HDA should be looking like this with more or less files depending on the number of Sections and scripts that you may have defined in your HDA:

  • expanded.hda - This is the main folder under which your HDA is expanded. If it uses the .hda extension, you can load it straight away in Houdini
    • houdini.hdalibrary - Just here to say this is a hdalibrary
    • INDEX_SECTION - Specify some basic information regarding the declared operator such it operator name, operator label, context, number of input and output, etc...
    • Sections.list - List files in this folder and how they should be evaluated by houdini
    • Sop_1hda_name - This is the folder under which you HDADefinition is expanded
      • Contents.dir - (Optional) This folder represent the content inside your HDA
        • Contents.createtimes - When were each children nodes created
        • Contents.houdini_versions - Which version of houdini was used to create each children nodes
        • Contents.mime - This file define most properties of the children nodes such as how they are connected, the values on the parameters, placement in the HDA.
        • Contents.modtimes - When were each children nodes last modified
        • Sections.list - List the files in this folder and how they should be evaluated by houdini
      • CreateScript - Automaticly created script defining how to create the HDA
      • DialogScript - This file define the ParmTemplateGroup on the HDA, with all the information relative to the list of parameters, default values and parameter behavior, etc...
      • ExtraFileOptions - Houdini internal file used to remember where was your cusor when editing files within the HDA Editor dialog
      • Help - (Optional) Help file for your HDA
      • InternalFileOptions
      • PythonCook - (Optional) This is the content to be evaluated when the node is used to programaticly generate contents.
      • PythonModule - (Optional) Whenever you are creating a PythonModule, the content is saved in this file.
      • Sections.list - List the files in this folder and how they should be evaluated by houdini
      • Tools.shelf - A file very similar to a "Shelf Tool", because it is one! This is the tool that is called when you ask to create the node
      • TypePropertyOptions - Various properties about the HDA

Expanded HDA are slower for Houdini to load as it need to compile it. Though, for development, it might be interresting to work with the expanded version as you can edit those files from an external editor, and changes will be reflected in Houdini.

Python Panel instead of Parameters

It is now possible to interact with an operator by using a PythonPanel (Qt UI) instead of the regular Parameter view. For doing so, you first need to create a new Panel.

<xml version="1.0" encoding="UTF-8">
<pythonPanelDocument>
    <interface name="my_ui" label="My UI" icon="MISC_python" shownetworkNavigationBar="true" help_url="">
        <script><![CDATA[
from hutil.Qt import QtWidgets


def onCreateInterface():
    widget = QtWidgets.QLabel("Hello World")
    return widget
        ]]></script>
        <help><![CDATA[]]></help>

        <!-- This is the part where you define all the operators that your UI can be used from. -->
        <showInParametersPane optype="Sop/hda_name"/>

    </interface>
</pythonPanelDocument>

Then when you select your operator, you should have an addional icon on the left of gear parm icon (looking like 2 slider). Click on it to enable/disable the python panel view.

Advanced HDA Functionality

Warning

This section still need to be written. Please come back later.

Managing operators

Over a HDA lifecycle, it's integration with Houdini might require you to define how it integrate with existing tools. For example, you might want to give preference to your newly created caching HDA over the default Houdini filecache.

Here are couple way to help integrate your tools with existing HDA:

Hide an operator

This method can be used to avoid an operator to be use. This can be the case with a deprecated tool. By hidding the operator, it won't be showing as an available operator in the UI. Though, the operator still remain install, which allow previously created node to still be working properly.

To hide an operator, you should use:

hou.NodeType.setHidden(True)

Uninstall an operator

Important

This last method will only work with HDA and can cause some issues in the user scene. Be careful when using it!

By uninstalling the HDA, the operator will fallback to the next available HDA Definition if the uninstalled one was current. In the case no other definition are available, a warning will be displayed to the user.

To fully uninstall an operator, you can use the following script:

# Finally uninstall all definition
for definition in node_type.allAvailableDefinition():
    # Handle the cases where multiple definition might be defined in a file
    for file_definition in hou.hda.definitionsInFile():
        # No problem if current definition is not current
        if not file_definition.isCurrent():
            continue

        # Check if the definition is being used by any node in the scene
        elif file_definition.nodeType().instances():
            raise RuntimeError

    # Finally uninstall the file
    hou.hda.uninstallFile(definition.libraryFilePath())

Create operator aliases

Adding an alias to an HDA can be a good solution when some of your tools are unavailable, but they are still invoked in the scene. Alternativly, aliases can be use to provide easy way for users to create some of your tool.

Aliases can be used in code, but are also visible in the user interface.

Let's take the "box" example in houdini to show how to create and remove an alias:

node_type = hou.nodeType("Sop/box")
node_type.addAlias("cube")

hou.node("/obj").createNode("geo").createNode("cube")

node_type.removeAlias("cube")