Setting the Expression Language
Parameter expressions may be written using either the Hscript expression language or the Python expression language. You can mix and match the languages, so some parameters in a node may use Hscript expressions while other parameters in the same node use Python expressions.
In HOM terminology, a parameter can be in one of two states: animated or not animated. An animated parameter has a set of keyframes. Each keyframe contains a time and an expression (as well as other information discussed later). A keyframe is active from its time up to the next keyframe, or until the end of the time range if there is no next keyframe. When Houdini evaluates a parameter at a particular time, it looks up the keyframe corresponding to that time and evaluates the expression. So, when someone says a parameter has an expression, he or she typically means that it has a single keyframe at time=0, and they're referring that that keyframe’s expression. The convenience functions hou.Parm.expression and hou.Parm.setExpression provide easy access to that expression.
There are two ways to control a parameter’s language, depending on whether or not the parameter is already animated. If it is not animated and you write an expression in it, Houdini uses the node’s expression language. The parameter dialog displays the node’s language as either an H (for Hscript expressions) or the Python logo (for Python expressions). Changing the node’s language does not affect parameters that already have expressions; it simply determines the language for new expressions you write. If a parameter’s language is different from the node’s language, Houdini will highlight that parameter in pink to make you aware of that difference.
You can control the default expression language for newly created nodes with a preference in Houdini’s main preference dialog.
If the parameter is already animated, you can change its language by right-clicking on it and selecting “Expression → Change Language to Python” or “Change Lanuage to Hscript Expressions”. For most expressions, changing the language will generate an error because of syntactical and API differences between Hscript expressions and Python. However, certain functions, like ch and the animation functions (cubic, bezier, etc.) have been carefully designed to use the same syntax in both Hscript expressions and Python. For those expressions, you change change the language without generating errors or changing the output of those parameters.
Single and Multi Line Python Expressions
With Python parameter expressions, there is one simple rule you need to
know: single lines are evaluated as standard expressions, and multiple
lines are evaluated as function bodies. For example, 2+2 and ch("ty") + 2
are valid Python expressions, but x=3 and x=3; x are not. However, if you
press Alt+e to bring up the multi-line editor, you can enter the following
Python function body:
if ch("ty") == 0: return 0 if ch("ty") < 0: return ch("tx") return ch("tz")From a Python function body you can run arbitrary Python statements, giving you full access to Python’s standard library. Beware that Houdini may evaluate the parameter more often than you expect.
Python Expression Namespaces
Python expressions run in a different namespace than the global namespace
provided by the Python shell. This way, you don’t have to worry about
Python global variables created in the shell affecting the output of
parameter expressions, and vice versa. Also, to reduce the length of
your Python parameter expressions, Houdini implicitly runs
from hou import * and from hou.session import * in the Python expression
namespaces. This means you can drop the hou. prefix in your Python
expressions, and you can call hou.session functions as though they were
defined locally. For example, in a Python expression you can write
ch("ty") instead of hou.ch("ty"). Similarly, Houdini imports the
following functions from Python’s math module: acos, asin, atan, atan2, ceil,
cos, cosh, degrees, exp, fabs, floor, log, log10, pow, radians, sin, sinh,
sqrt, tan, tanh Because the expression operates in a different namespace,
Houdini’s global Python namespace is not polluted by these imports.
Tip
If you really want to access a global variable from a Python expression,
you can run import __main__ to get access to Houdini’s global
Python namespace. For example, if foo is a function defined in
your pythonrc.py file, you can access foo from a Python expression via
__main__.foo.
Note that you can also access the Python expression namespace from the global namespace with hou.expressionGlobals. This function lets you add functions that are easily callable from Python expressions. For example:
# Put the following in your $HOME/houdiniX.Y/python2.5libs/pythonrc.py file: def clamp(value, min, max): return (min if value < min else (max if value > max else value)) hou.expressionGlobals()["clamp"] = clamp
Also consider the following example. Normally, to access math.pi
from a Python expression, you would either have to create a multi-line
expression that imports math and then returns math.pi, or do it in one line
with __import__("math").pi. By putting the following in pythonrc.py, you
can simply write pi.
import math hou.expressionGlobals()["pi"] = math.pi
String Parameter Expressions
Note that when Houdini evaluates string parameters without expressions,
it will do string expansion on the result. So, if the unanimated string
parameter contains image$F.pic, Houdini will expand $F, regardless of whether
or not the node’s language is set to Hscript expressions. However, if you
animate the string parameter, using the Hscript expression language,
the expression needs to be "image$F.pic", because image$F.pic is not a
valid Hscript expression evaluating to a string. (To convince yourself
of this, run:
echo `image$F.pic`
and
echo `"image$F.pic"`
...in a textport.) Houdini’s UI goes through great pains to automatically
convert between unexpanded strings and Hscript expressions for you, and
the UI often tries to hide the actual expression. (To see the expression,
you can inspect the hou.Keyframe with hou.Parm#keyframes.) For
Python string expressions, you also need to write a valid Python expression,
such as "image %d" % frame(). Thankfully, Houdini will let you see and edit
those expressions, and it does not second-guess your intentions and
automatically modify those expressions for you.
Local Variables
You can access Hscript expression local variables from Python with
hou.lvar. For example, you can write the Hscript expression $TX
in Python as lvar('TX'). Note that hou.lvar cannot access hscript
global variables; for evaluate them, use hou.expandString.
Many local variables in Houdini correspond to a SOP or POP that iterates
over a number of points or primitives, evaluating the nodes parameters
for each iteration. Each time the parameters are evaluated, Houdini uses
a different value for the local variable, corresponding to the current
point or primitive. The hou module provides hou.SopNode.curPoint,
hou.SopNode.curPrim, and hou.PopNode.curPoint, giving you
access to a hou.Point or hou.Prim object. So, for example,
lvar('Cr') in a Point SOP could also be written as
curPoint().attribValue('C')[0]. While this approach is more verbose
and has additional overhead, it is more generic, giving you access to
information in points and primitives that may not be available through
local variables.
Interrupting Expression Evaluation
If you call Python code that takes a long to evaluate, or it goes into an infinite loop, you can press Escape to interrupt expression evaluation.