Houdini for TD - API

Note

This article is part of the serie Houdini for TD

Sourcing SideFX modules

Modules provided by SideFX can be sourced from the folder: `$HFS/houdini/python3.7libs`.

Important

Be aware that using the `hou` module require a houdini license of some sort

Sourcing your code in Houdini

When developing python code, there is various way for your to source it in Houdini.

My recommended solution is to add the part to your source in the `$PYTHONPATH` environmnment variable. This way, your python code should be available to any python interpreter, including the one used by Houdini.

Houdini can also source code coming from sources in `$HOUDINI_PATH/pythonX.Xlibs`, which can be useful when organizing your code in packages. Depending on your configuration, the code in this folder should only be visible to Houdini python interpreter. Be sure to use the right python version number.

If you want code to only be accessible into a single Houdini scene, you can place it into `hou.session` via the Python Source Editor.

For HDA, python code can be placed into the PythonModule file, and referenced on the node by using `hou.phm()`.

Last but not least, Houdini has various Python operators that can be used to evaluate python code.

"hou" package

The `hou` module is the main way for you to interact with Houdini. It is accessible by default from anywhere in Houdini and in many cases, you don't need to import it. Though I am recommending to properly import it for cleanness:

import hou

We won't be going threw every single function and classes here as it would be very long and boring, but we will still focus on some key elements.

SideFX has done a really good job at documenting the module and you can find the help for it here: https://www.sidefx.com/docs/houdini/hom/hou/index.html

Accessing houdini objects

Let's starts with some simple example by selecting various objects in houdini.

import hou

# Let's start by selecting the obj network manager node
obj_node = hou.node("/obj")

# Then we will be creating a "geometry" node of type "geo"
geo_node = obj_node.createNode("geo")

# We can rename the node
geo_node.setName("my_geo")

# Let's get and change a parameter
scale_parm = geo_node.parm("scale")
scale_parm.set("2")

Nodes and parameters in houdini are like a file system with folders and files, where nodes are the folders, and parameters the files. Nodes and parameters can be references from the hou modules using their absolute path in the scene, or from other nodes/parameters using their relative path.

Here are various way to get the geo_node we created earlier

# Absolute path
hou.node("/obj/my_geo")

# Relative path
obj_node.node("my_geo")
obj_node.node("./my_geo")

# Let's get the parent node from geo_node
obj_node.node("..")
obj_node.parent()

# Getting parameters
hou.parm("/obj/my_geo/scale")  # Absolute
obj_node.parm("my_geo/scale")  # Relative
geo_node.parm("../<some_parameter>")  # There is no parameter on /obj node...

Here are some more useful function to know before we keep moving:

# List all direct children under obj_node
obj_node.children()

# List all children recursively under obj_node
obj_node.allSubChildren()

# Return list of parameters on node
geo_node.parms()

# Get the node type
geo_node.type()

# Get the node type category
geo_node.type().category()

Creating parameters on nodes

Let's now see how to modify the user interface by adding/removing parameters.

# The parmTemplateGroup represent
ptg = geo_node.parmTemplateGroup()

# Let's define the new parameter
float_pt = hou.FloatParmTemplate("my_float", "My Float", 1)

# Add the parameter to the parmTemplateGroup
ptg.addParmTemplate(float_pt)

# Update parm template group on node
geo_node.setParmTemplateGroup(ptg)

# To remove the parameter
ptg = geo_node.parmTemplateGroup()
ptg.remove("my_float")
geo_node.setParmTemplateGroup(ptg)

Note

The same way as Nodes are defined by a NodeType, Parameters are defined by a ParmTemplate.

Relationship between classes

The diagram bellow try to show the relationship between each major classes in the hou module. Those are not the true relationship, but more an easy to understand map of it. For a more detail relationship, please refer to the HDK.

    classDiagram
        class NetworkMovableItem
        class Node{
            type(): NodeType
            parm(): Parm
            parmTemplateGroup(): ParmTemplateGroup
        }
        class NodeTypeCategory{
            nodeTypes(): List[NodeType]
        }
        class NodeType{
            category(): NodeTypeCategory
            definition(): Optional[HDADefinition]
            allInstalledDefinitions(): List[HDADefinition]
            instances(): List[Node]
        }
        class HDADefinition{
            nodeType(): NodeType
            nodeTypeCategory(): NodeTypeCategory
        }
        class Parm{
            node(): Node
            parmTemplate(): ParmTemplate
        }
        class ParmTemplate
        class ParmTemplateGroup{
            parmTemplates(): List[ParmTemplate]
        }

        NetworkMovableItem <|-- Node: Inheritance

        HDADefinition "1..*" <--* "1" NodeType: Composition
        HDADefinition --o "1" NodeTypeCategory: Aggregation
        NodeTypeCategory "1" <--* "1" NodeType: Composition
        NodeType "1" <--* "\*" Node: Composition

        Node "1" --* ParmTemplateGroup: Composition
        HDADefinition --o "1" ParmTemplateGroup: Aggregation
        ParmTemplateGroup --o "\*" ParmTemplate: Aggregation
        ParmTemplate "1" <--* "1" Parm: Composition

        Node "1" <--> "\*" Parm: Association

hou.Node

hou.Node is the class that represent most nodes in Houdini. You can get any node in the scene by calling:

hou.node("/absolute/path/to/node")
# Or
hou.node("../relative/path/to/node")

A Node is always caracterized by a hou.NodeType, which you can get by calling the method `hou.Node.type()`. In some way, hou.Node is and instance of a hou.NodeType.

When fetching a node, you will get one of the subclass of hou.Node:

  • ObjNode - Object context
  • LopNode - Lop context
  • SopNode - Sop context
  • RopNode - Rop context
  • etc...

With the example of the RopNode, you will have addional method available such as `hou.RopNode.render()`, which is used to trigger the Render from a node.

hou.Node inherit from hou.Item which is the base class for any graphical items in the networkEditor. This is the class which give the ability to move the node around or set it's color. Other example of hou.Item are hou.NetworkBox or hou.StickyNote.

Each node instance by default inherit the hou.ParmTemplateGroup from the hou.NodeType, but it can also have it's own instance, which allow to customize the parameter interface per node.

You can read more in the Node Official Documentation.

hou.NodeType

Every single hou.Node is defined by a hou.NodeType. Node types are caracterized by a hou.NodeTypeCategory which determine in which context a node can be created, but also affect the node behavior.

We can classify hou.NodeType in to group:

  • builtin/compiled - They are usually provided by SideFX or built using Houdini Development Kit.
  • HDA - They can be built from Houdini itself.

HDA are defined by at least one hou.HDADefinition, but only one definition can be active at the same time. You can use `hou.NodeType.allInstalledDefinitions()` to get the full list of definition or `hou.NodeType.definition()` to get the active one.

You can read more in the NodeType Official Documentation.

hou.Parm

Every parameter is caracterized by a hou.ParmTemplate, which will determine the type of values and look of a parameter. You can access the parameters on any node by calling:

my_node.parm("parm_name")
# Or
hou.parm("path/to/node/parm_name")

Parameter values are stored on each instance of the parameter, unless they are at default value as defined on hou.ParmTemplate. Value can be fetched and set:

# To fetch the value
my_parm.eval()
# Or
my_node.evalParm("parm_name")

# To get the values
my_parm.set(value)

In some case, the keyframes or expression can be set on parameters. In those cases, the `eval` functions will return the evaluated value, which is the interpolation of the animation or the returned value from the expression.

# This will return the a list of hou.Keyframe
my_parm.keyframes()

# This will return the expression set on the parameter
my_parm.expression()

In some cases, the parameter cannot be edited, if its inside a lock HDA for example.

You can read more in the Parm Official Documentation.

hou.ParmTemplate

The ParmTemplate caracterize a Parameter by setting the type of value and addional interaction properties. It exists as many hou.ParmTemplate as there is parameter types in houdini. Here is a non-exausive list:

  • hou.ButtonParmTemplate
  • hou.FloatParmTemplate
  • hou.StringParmTemplate
  • etc...

You can read more in the ParmTemplate Official Documentation.

hou.ParmTemplateGroup

The ParmTemplateGroup is used to organize all the parameters on a Node. It allow to create folders, add extra parameter, hide others. Will see more about them later on.

You can read more in the ParmTemplateGroup Official Documentation.

Note

The ParmTemplateGroup can be updated on a Node to update a specific node parameter interface, or you can update it on the HDADefinition to update the HDA definition and all nodes of this type.

Utility packages

In the folder `$HFS/houdini/python3.7libs`, you will find many useful utility packages. Those packages are often use by Houdini itself to perform various tools interaction.

The perfect example is the module `soptoolutils` with the function `genericTool` which is invoked when most SOP nodes are created.

The module `toolutils` has a function `sceneViewer` or `networkEditor` which can return the current active Pane Tab of those type.