On this page |
Overview ¶
You can enter short bits of code, like mathematical expressions, in parameters to compute their values using math and variables such as the current frame number, the point number, random numbers, and so on. For example, to make a sphere rise over time without having to manually keyframe it, you could set its Y Position to equal the frame number divided by 5.
Languages ¶
Houdini lets you write expressions in two different languages: traditional HScript expressions, and Python. In addition, some specific nodes let you write VEX snippets to control the node behavior.
HScript expressions |
The traditional way to write expressions. Uses the expression functions. |
Python |
A more powerful but more verbose way to write expressions. Uses the Houdini Object Model API and any functions built-in to Python. |
VEX |
A fast, compiled language. Only available in certain parameters on specific nodes. |
By default, parameters in Houdini use the traditional HScript expression language explained below. To switch to use Python in a specific parameter, node, or everywhere, see Python parameter expressions.
HScript expression example ¶
-
Create a new Geometry object and dive inside.
-
Create a Grid node.
-
In the parameter editor, set the Grid node’s Size fields to:
$F / 10
This makes the grid’s size relative to the current frame number. Trying playing back the animation using the playbar at the bottom of the main window.
String parameters ¶
-
In numeric parameters (such as position, rotation, scale), the text in the parameter is evaluated as an expression.
-
In string parameters (such as filenames, or the text created by the Font node), the text in the parameter is treated as text. Variables are expanded, but to use math or expression functions to generate part of the text you must place the expression within backticks. For example:
frame`padzero(5, $F)`.pic
…giving you filenames such as
frame00001.pic
,frame00002.pic
, and so on.
(See expressions in filenames for more information about using variables and expressions in filename parameters).
Variables and attributes ¶
Your expressions can use variables provided by Houdini:
-
Global variables such as
$F
(the current frame number) and$T
(the current time in seconds). See the list of global variables below. -
Geometry attributes. In HScript expressions on geometry you can reference the value of an attribute using
@attributename
. For example, you can use@pscale
to get the value of thepscale
(point scale) attribute on the current point.For vector attributes such as
P
(position), you can use dot notation to grab a component, for example@P.x
. You can use.x/.y/.z
or.1/.2/.3
or.r/.g/.b
, whichever makes sense for the type of data. -
Local variables. Nodes often provide variables that are useful for expressions on nodes of that type. For example, a node that operates over the points in a geometry will have a
@ptnum
variable representing the point number of the current point. The help for a node will list the local variables you can use in expressions on that type of node. -
Environment variables such as
$HIP
(the directory containing the scene file) are available to expressions.
Parameter/channel references ¶
In HScript expressions you can reference the value of a parameter on a node using the ch function. This can be useful to make a number on one node follow or be relative to a number on another node.
Tip
You can create your own custom parameters to reference in your expressions. See spare parameters.
To... | Do this |
---|---|
Create a channel reference automatically |
|
Create a channel reference manually |
When typing an HScript expression, use the ch function to get the value of another parameter. The argument to ch("tz") To get the X transform of the ch("/obj/lamp/tx") To get the Y rotation from the ch("../grid1/ry") (To get a string value, use chs.) |
Find out the internal name of a parameter |
To reference a parameter manually, you must know its internal name. You can get this by hovering over the parameter label, or by clicking ▸ Edit parameter interface in the parameter editor, clicking the parameter, and looking in the Name field. |
Multi-line expressions ¶
The expression language is usually used for short one-line formulas to expression a relationship between a parameter value and other values (for example, making a ball move by setting its X position to $T * 2
). If you want to do complicated scripting in a parameter expression, you may want to switch the parameter to use Python instead of the traditional expression language.
However, if you do want to do complex things with the traditional expression language, you can use multi-line expressions with blocks, if
statements, and for
loops.
Tip
For both HScript and Python expressions, you can press ⌃ Ctrl + E in a parameter, or right-click the parameter and choose Expression ▸ Edit Expression to open the expression in a multi-line floating editor.
-
A block is a set of sub-statements, inside curly braces (
{
and}
). -
You must separate sub-statements with a semicolon character (
;
). -
Sub-statements may consist of:
-
Assignment. The right-hand side of the assignment can use expression syntax and functions. Specify the variable type (
float
orstring
) before the name is optional for floats but required for strings.For example:
size = 0; float frame = ch("outputframe"); string name = ch("name");
Assigned variables are local to the outer
{}
block. -
You can also use in-place modifying assignments such as
j += 5;
andi -= 1;
, and C-style in-place increment/decrement such asi++;
andj--;
as statements. -
if...then...else
statements. See if statements below. -
for
andwhile
loops. See for loops below. -
return
statements. The right-hand side of thereturn
can use expression syntax and functions. When thereturn
statement is executed, its expression is evaluated and used as the overall value for the outer{}
block.You can have multiple and early
return
statements, for example inside anif
block:{ # ... if (evalmode == 4) { float slope = (ch("../inputrangey") - miniframe) / (ch("../outputrangey") - minoframe); return miniframe + ($FF - minoframe) * slope; } # ... }
(If no
return
statement executes, the outer{}
block will evaluate to0
.) -
A
#
character starts a line comment. The rest of the line after the#
character is ignored.
-
if statements ¶
Note
The expression language has an if function, of the form:
if(‹expression›, ‹true_value›, ‹false_value›)
The difference between an if
statement and the function is that in the above function, the conditional expression, the true expression, and the false expression are all always evaluated. In the if
statement described below, the conditional expression is evaluated, and then depending on its truth value, only one of the branches is executed.
A multi-line if
statement is similar to C’s:
-
if
followed by a boolean expression in parentheses (()
). -
A statement or block (group of statements inside
{}
) that is executed if the expression evaluates to non-zero (considered “true”). -
Zero or more optional
else if (‹expr›) ‹stmt›
branches that are evaluated in turn if the previous branch did not execute. -
An optional
else ‹stmt›
branch that executes if no other branch executed.
{ size = 0; if ($F > 10) { size = 23; } else if ($F > 20) { size = 47; } else { size = 50; } return size; }
for and while loops ¶
The for
loop in a multiline expression is similar to C’s:
-
for
followed by parentheses (()
) containing three expressions separated by semicolon (;
) characters. For example(i = 0; i < 10; i++)
.-
The first part inside the parentheses is executed before looping begins, usually to set the initial value of a looping variable.
-
The second part is evaluated each time through the loop. If the expression is true (non-zero), the loop exits.
-
The third part is executed after each loop, usually to increment the looping variable.
-
-
A statement or block (
{}
) which is executed each time through the loop. -
You can use
break
andcontinue
within a loop.
{ float out = 0; for (i = 0; i < 10; i++) { out += i; } return out; }
The while
loop is also similar to C:
-
while
followed by an expression inside parentheses (()
) and a statement or block ({}
). At the start of each loop, if the expression evaluates to true (non-zero), the following statement/block is executed. -
You can use
break
andcontinue
within a loop.
{ float k = ch("parm"); float i = 0; while (i < k) { i++; if (i % 2 == 0) continue; } return i; }
Tips ¶
-
It’s easy to modify geometry in geometry nodes using HScript expressions and local variables in parameters. However, it’s much more efficient to modify geometry using a VEX snippet in a node such as the Point Wrangle or Attribute Wrangle.
Future versions of Houdini will probably move toward encouraging use of VEX to modify geometry rather than parameter expressions.
-
You can check the value of an expression by choosing Window ▸ HScript Textport and then typing:
echo `expression`
-
Houdini always creates each frame “from scratch” using the “recipe” of the network. Expressions always operate on the values they get from the initial setup of the node, not from the previous frame.
For example, if you set up a Point geometry node to add a random offset to the Y position of each point in a grid:
Position Y
@P.y + rand(@Frame * @ptnum)
…when you play back the animation, the points will jump about randomly, instead of smoothly moving up and down. This is because at each frame the network starts with the flat grid and then applies the random movement to it. The expression does not run on the geometry from the previous frame.
Quoting in HScript expressions ¶
Strings ¶
Text inside single quotes ('
) is not expanded. Text inside double quotes ("
) has variables expanded. A double-quoted string is considered one argument.
A backslash character (\
) escapes the next character. For example, to use double-quotes in a string:
"I had a \"great\" time."
When a string doesn’t require variable expansion, use single quotes to speed up evaluation.
If you have two quoted strings next to each other with no spaces, they are considered a single argument. In this example…
set foo = "Hello world" echo '$foo='"$foo" $foo=Hello world
…the echo command has one argument: '$foo=Hello world'
.
Embedding ¶
In the HScript command language, text inside backticks is evaluated as an expression. For example:
echo `strlen("$foo")`
Tip
Scripting using the HScript command language is deprecated. You should use Python instead.
The string parser cannot decode nested quotes such as in the following (horribly contrived) example:
echo `system("echo `ls`")`
…however, it is possible to accomplish this with very careful usage of backquotes (and sometimes multiple backquotes in a row) to protect quote symbols from various levels of evaluation:
echo `system('echo \`ls\`')`
HScript global variables ¶
Tip
Some global variables have equivalents that start with @
to match variables available in VEX snippets.
Playback ¶
Note
You can run into a precision issue when computing transforms based on the value of $FF
(floating point frame number). With, say, 30 motion segments, each segment is 0.00138888 seconds. At frame 1800 of a long animation, the segment times will be numbers like 75.00138888888. If this is truncated to single precision anywhere in the pipeline, it would be rounding to something like 75.0014, which will create strobing.
To fix precision issues with floating point frames, $FF
always returns a precision adjusted value. This can cause problems for double precision evaluations. To avoid precision issues, use $T
(floating point time in seconds) instead. Replace $FF
with $T * $FPS + 1
(or use hou.frame(True)
in python) to remedy strobing values.
|
|
Description |
---|---|---|
|
Playback speed in frames per second (as set with the Playbar controls). |
|
|
Frame number of the first frame of animation (as set with the Playbar controls). $NFRAMES (the number of frames in the animation) = $FEND - $FSTART + 1. |
|
|
Frame number of the last frame of animation (as set with the Playbar controls). |
|
|
The current frame, (as set with the Playbar controls). This is a very useful variable, especially for rendered picture filename numbering. |
|
|
|
Floating point frame number, rounded to 6 digits after the decimal place. See also the note about |
|
Legacy variable for behaviour of |
|
|
Number of frames in the animation. |
|
|
Frame number of the first frame shown in the playbar. The playbar can show a subset of the total number of frames, allowing you to focus on a particular section of a long animation. $RFSTART and $RFEND control the subset of frames shown in the playbar. |
|
|
Frame number of the last frame shown in the playbar. |
|
|
|
Current time in seconds. Equals ($F-1)/$FPS |
|
Total length of animation in seconds. |
|
|
Start time of animation in seconds. |
|
|
End time of animation in seconds. |
General ¶
|
Contains the name of the current take. |
|
|
The mathematical constant e (2.71828…). |
|
|
The directory where Houdini is installed. |
|
|
|
|
|
The directory containing the current scene file. |
|
|
The full path of the current scene file, including the file extension. |
|
|
The name of the current scene file without the extension. You can use this to build filenames with different extensions based on the scene name. |
|
|
Your home directory. |
|
|
The project directory. |
|
|
The mathematical constant pi (3.1415926…). |
Channels ¶
|
Operator String. Contains the current OP’s name. |
|
Current channel name. |
|
In value (value at start of segment). |
|
Out value. |
|
In slope |
|
Out slope |
|
In acceleration |
|
Out acceleration |
|
Local time - not including stretch or offset |
|
Start time of segment |
|
End time of segment |
|
Local start time of segment |
|
Local end time of segment |
|
Previous segment start time |
|
Next segment end time |
COPs ¶
|
Start frame of the current COP. |
|
End frame of the current COP. |
|
Number of frames for the current COP. |
|
Number of frames available from the first input COP. |
|
Gets the global frame increment value. |
|
Current image width. |
|
Current image height |
Render nodes ¶
|
Current frame being rendered. |
|
Number of frames being rendered. |
See also |