On this page |
Overview ¶
In Houdini, you can use expressions in parameters and in VEX snippets to accomplish complex and interesting effects with just a bit of math. This page demonstrates a few useful formulas and tricks to use in expressions.
-
See expressions for the basics of HScript expressions. See VEX for more about the VEX language.
-
On this page the expressions listed often have
ch()
functions to access values from parameters. See spare parameters for how to set up custom parameters your expressions can use. -
Future versions of Houdini will move toward having users use VEX to modify geometry instead of allowing HScript expressions to modify local variables, because VEX is much faster.
Channel lookups ¶
Equivalencies and differences ¶
Expression |
VEX |
|
---|---|---|
Current frame |
|
|
Current time |
|
|
Bounding box |
|
|
Centroid |
|
vector cent = getpointbbox_center(0); // cent.x, cent.y, cent.z |
Size |
|
vector size = getbbox_size(0); // size.x, size.y, size.z |
Corners |
|
vector min; vector max; getbbox(0, min, max); // min.x, min.y, min.z, max.x, max.y, max.z |
Raise to power |
|
|
Trig functions |
Degrees |
Radians You can convert degrees to radians using the radians function. |
Random numbers ¶
-
For examples of randomization in HScript expressions and VEX, open
$HH/help/files/RandomExample.hip
.
Expression |
VEX |
---|---|
|
|
|
|
The random number functions always return the same number given the same seed value. This makes “random” values repeatable between playbacks. However, to make sure that different points/particles/objects/frames etc. get different random values, you must vary the seed.
Choosing a random seed ¶
The current frame number ($F) is usually a good seed value. However:
-
If you need random values for sub-frames, use the fractional frame number
$FF
instead of$F
. -
If you need more than one random value, such as R, G, and B values for a random color, give each call to rand a different seed value by multiplying or adding to
$F
, for examplergb(@Frame, @Frame * 10, @Frame * 100)
. Otherwise each call will return the same number and the color will be gray. -
If you need a random number to span from
-X
toX
, you can userand(seed) * (2 * X) - X
. -
The random number is in the range 0-1. Use the
fit01(n, newmin, newmax)
function to map the random number to a different number range.The
fit10
function is similar but reverses the mapping. For example,fit10(.3, 5, 20) == 15.5
.The
fit(n, oldmin, oldmax, newmin, newmax)
is a more general form that lets you map any number from one range to another range. For example,fit(3,1,4,5,20) == 15
.The fit functions exist in both the HScript expression language and VEX.
Randomizing values across geometry ¶
The following will randomize every primitive color on every frame.
In HScript expressions:
rand(@primnum) rand(@primnum * 10) rand(@primnum * 100)
In VEX:
@Cd.r = random(@primnum * @Frame); @Cd.g = random(@primnum * 10 * @Frame); @Cd.r = random(@primnum * 100 * @Frame);
Cycling values ¶
-
For examples of cycling values in HScript expressions and VEX, open
$HH/help/files/ModulusExample.hip
.
The modulus operator a % b
is the same in HScript expressions, VEX, and Python. It returns the remainder after dividing a
by b
. This is very useful because given a value that increases continuously (such as the frame number), you can produce a value that wraps around a range of values.
Note
If you try this with a floating point value, you can get unexpected results. For example, 3.14 % 1
returns 0.14
, and 34.999 % 5
returns 4.999
.
For example:
|
0 |
1 |
2 |
3 |
4 |
5 |
6 |
---|---|---|---|---|---|---|---|
|
0 |
1 |
2 |
0 |
1 |
2 |
0 |
Ripples ¶
-
For examples of ripples in HScript expressions and VEX, open
$HH/help/files/RippleExample.hip
.
To get mathematical radiating ripples, base the point position on a sin function using the distance of the point from the center of the surface.
Position Y |
|
---|
To animate this, add a time-based variable to the expression:
Position Y |
|
---|
Arcs, circles, and spirals ¶
-
For examples of ripples in HScript expressions and VEX, open
$HH/help/files/ArcExamples.hip
.
You can use sin
and cos
to generate positions along an arc or circular path.
Position X |
|
---|---|
Position Z |
|
(This may be useful for creating interesting effects, however you can often accomplish similar effects by creating arcs and circles with the Circle SOP. For example, you can place items in a circle by creating a polygonal circle and then copying the items to the circle’s points.)
You can create a spiral by increasing the position in the third dimension as you control the other two with sin
and cos
.
X |
|
---|---|
Y |
|
Z |
|
Logarithmic spiral in VEX ¶
-
To play with this example, open
$HH/help/files/logSpiral.hip
.
The example uses channel references to get values from parameters.
// Expose point normals @N = @N; // Natural log float e = 2.718281828; // Calculate point positions of log spiral @P.x = chf("a") * pow(e, chf("b") * @ptnum * .001) * sin(@ptnum); @P.z = chf("a") * pow(e, chf("b") * @ptnum * .001) * cos(@ptnum); // Calculate general size of each instance @pscale = chf("sc") * chf("a") * pow(e, chf("b") * @ptnum * .001); // Look up color table based on point position @Cd = chramp("color_spectrum", @ptnum/(@numpt-1.0));
Waveforms ¶
-
For examples of using waveforms in HScript expressions and VEX, open
$HH/help/files/WaveFormExamples.hip
.
Waveforms are very useful for generating mathematical repeating placement, size, or motion.
Step function ¶
A step function takes a continuous input and converts it to an output in discrete steps.
floor(@P.x * freq) * amplitude
Sin wave ¶
-
For examples of sin waves in HScript expressions and VEX, open
$HH/help/files/SinFunctionExample.hip
.
The sin
(and cos
) function are useful for creating of all kinds of shapes. You can use the basic sin
function to transform a line or surface into an oscillating wave.
The general form for a geometric sin wave is:
sin ( @P.x * frequency ) * amplitude + offset
For wave motion, you could use this expression:
sin ( @Time * frequency ) * amplitude + offset
…where:
@P.x
The basis for the wave: to animate the geometry of the wave, this could be set instead to (@P.x + @Frame
).
frequency
Controls the number of waves. You could set this to the bounding box position, $BBX, to make the waves more frequent towards the end of the line.
amplitude
Controls the height of waves. You could set this to the bounding box position, $BBX, to flatten the waves toward the end of the line, or the current frame, @Frame, to make the waves larger as the animation progresses.
offset
Translates the waves “up” or “down”.
Other waveforms ¶
A square wave alternates between two values:
abs(floor(@P.x * freq + offset) % 2 * amplitude))
A sawtooth wave increases and then resets:
@P.x - floor(@P.x)
A triangle wave bounces back and forth linearly:
abs(@P.x * freq % amplitude - 0.5 * amplitude)
Geometric deformations ¶
-
For examples of deformations in HScript expressions and VEX, open
$HH/help/files/Deformation_Examples.hip
.
You can alter point positions using HScript expressions in the Point SOP, or using VEX in the Attribute Wrangle SOP, to create geometric deformations such as shear, taper, twist, squash, and bend.
Note
You can get the common deformations much more easily through the Twist SOP. However, you can use these expressions if you need to customize or elaborate on the simple deformations.
Remember that the equivalent of $BBX
in VEX is relbox(@P).x
.
To shear along X:
Pos X |
|
---|
To taper along Y:
Pos X |
|
---|---|
Pos Z |
|
To squash and stretch along Y in HScript:
Scale X |
|
---|---|
Scale Y |
|
Scale Z |
|
In VEX:
v@scale = @scale; @scale.x = set( 1/sqrt(ch("strength"))); @scale.y = ch("strength"); @scale.z = set(1/sqrt(ch("strength"))); @P.x *= @scale.x; @P.y *= @scale.y; @P.z *= @scale.z;
To twist along Y in HScript (note that you use sin
in one axis and cos
in the other):
Pos X |
|
---|---|
Pos Z |
|
In VEX:
v@min = {0.0, 0.0, 0.0}; v@max = {0.0, 0.0, 0.0}; getpointbbox(0, @min, @max); v@cent = (@max + @min) / 2.0; f@twistX = cos(radians(chf("strength")) * (relbbox(@P).y - 0.5)); f@twistZ = sin(radians(chf("strength")) * (relbbox(@P).y - 0.5)); @P.x = (@P.x - @cent.x) * @twistX - (@P.z - @cent.z) * @twistZ + @centroid.x; @P.z = (@P.x - @centroid.x) * @twistZ + (@P.z - @centroid.z) * @twistX + @centroid.z;
To bulge and pinch along Y in HScript:
Pos X |
|
---|---|
Pos Z |
|
In VEX:
float PI = 3.1415926535897932384; @P.x += (sin(relbbox(@P).y * PI) * (1.0 / chf("bulge_factor")) - 1.0) *(relbbox(@P).x - 0.5); @P.z += (sin(relbbox(@P).y * PI) * (1.0 / chf("bulge_factor")) - 1.0) *(relbbox(@P).z - 0.5);
To bend along Y in HScript:
Pos X |
|
---|---|
Pos Y |
|
In VEX:
@P.x *= cos(radians(relbbox(@P).y * ch("strength"))) - @P.y * sin(radians(relbbox(@P).y * ch("bend_factor"))); @P.y *= sin(radians(relbbox(@P).y * ch("strength"))) + @P.y * cos(radians(relbbox(@P).y * ch("bend_factor")));