Houdini VEX sink

· Houdini MOC · Houdini VEX · Houdini VEX reference · #note/sink · #code/vex


Data types

int Integer values
float Floating point scalar values
vector2 Two floating point values
vector Three floating point values
vector4 Four floating point values.
array A list of values
struct A fixed set of named values (class)
matrix2 { {1,0}, {0,1} }
matrix3 { {1,0,0}, {0,1,0}, {0,0,1} }
matrix { {1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1} }
string A string of characters
dict A dictionary mapping strings to other VEX data types
bsdf A bidirectional scattering distribution function


@v = {1, 1, 1}
v@v = set(x, y, z)

Specifying VEX Data Types

The following characters are used to cast to the corresponding data type.

float       f@name    // Floating point scalar values.
vector2     u@name    // Two floating point values. Could be used to store 2D positions.
vector3     v@name    // Three floating point values. Usually positions, directions, normals, UVW or colors.
vector4     p@name    // Four floating point values. Usually rotation quaternions, or color and alpha (RGBA).
int         i@name    // Integer values (VEX uses 32 bit integers).
matrix2     2@name    // Four floating point values representing a 2D rotation matrix.
matrix3     3@name    // Nine floating point values representing a 3D rotation matrix or 2D transform matrix.
matrix      4@name    // Sixteen floating point values representing a 3D transform matrix.
string      s@name    // A string of characters.

1/100 results in integer, 1/100.0 results in float. See #Operator type interactions

Type casting

int a, b;
float c;
c = (float)a / (float)b; // float(a) is unnecessary
// type cast a function
float n;
n = noise(noise(P));
n = noise(vector(noise(P)));


Dot operator

// vector
v = set(v.x, v.y, v.z);
v = set(v.r, v.g, v.b);

// vector2
v2 = set(v2.x, v2.y);
v2 = set(v2.u, v2.v);

// vector4 forth element
f = v4.a;
f = v4.w;

// matricies
m[0][0] = m.xx;
m[2][2] = m.zz;
m[3][0] = m.ax;

v.zyx   = set(v.z,  v.y,  v.x);
v4.bgab = set(v4.b, v4.g, v4.a, v4.b);


The logical (&&, ||, and !) and bitwise (& |, ^, and ~) operators are only defined for integers
All bool operations are casted to integers!

Operator type interactions

float * int = float
int * float = int

vector * scalar = vector

v2 * v4 = v4
The “missing” component(s) on the smaller vector are filled in as {0.0, 0.0, 0.0, 1.0}


User interface pragmas

#pragma opname   noise_surf
#pragma oplabel  "Noisy Surface"

#pragma label    clr          "Color"
#pragma label    frequency    "Frequency"

#pragma hint     clr          color
#pragma range    frequency    0.1 10

surface noise_surf(vector clr = {1,1,1}; float frequency = 1; export vector nml = {0,0,0})
    Cf = clr * (float(noise(frequency * P)) + 0.5) * diffuse(normalize(N));
    nml = normalize(N)*0.5 + 0.5;

Channel Shortcut Syntax

This is used to hint at the data type of auto generated wrangle parameters.

ch('flt1');             // Float
chf('flt2');            // Float
chi('int');             // Integer
chv('vecparm');         // Vector 3
chp('quat');            // Vector 4 / Quaternion
ch3('m3');              // 3x3 Matrix
ch4('m4');              // 4x4 Matrix
chs('str');             // String
chramp('r', x);         // Spline Ramp
vector(chramp('c', x)); // RGB Ramp

Sample functions

Random Directed Vectors

Sample Direction Uniform

Sample Direction Uniform
This is a great way of getting “random” vectors but you need the vectors to be “clamped” to a certain range of “spread”.
To illustrate this, we’ll use a buncha points on a grid and “shoot” (aka move) them out “randomly” using sample functions.

vector2 u = rand(@ptnum);
@P = sample_direction_uniform(u);

Sample Direction Uniform.jpg|400

Sample Hemisphere

Sample Hemisphere

This function takes a center and a bias. Think of “center” in sample functions as “direction” – so {0, 1, 0} is up, {0, -1, 0} is down – and bias is simply the “angle of spread”.

vector2 uv = rand(@ptnum);
float bias = @Frame;
@P = sample_hemisphere({0, 0, 0}, bias, uv);

Sample Hemisphere.gif|400

Sample Direction Cone

Sample Direction Cone

This is probably the most useful, instead of bias we just use angle instead to achieve something similar. This time, we’ll scatter upwards using {0, 1, 0} as the center.

vector2 uv = rand(@ptnum);
float angle = 90; // the "spread" of the cone @P = sample_direction_cone({0, 1, 0}, radians(angle), uv);

Sample Direction Cone.gif|400

We could imagine using this to shoot out random particles, so instead of @P we could assign it to @v as initial velocity to a DOP – while constraining how far they spread.
But what happens if we want the magnitudes to be the same? Right now, we have some vectors that are ahead of others because it’s a dome-like spread.
We achieve this by only varying v in the uv.

vector2 uv = set(1, rand(@ptnum));
@P = sample_direction_cone({1,0,0}, radians(angle), uv);

Sample Direction Cone2.gif|400

Now the values are “clamped” along whichever axis the center is on e.g. all the points have the same @P.x value – since we are scattering in {1, 0, 0}.
Another way of thinking about this, if we have particles getting shot out in +x direction, they can only vary/wiggle up-down (y) or left-right (z) but how far they go (x) is always the same across all points.
At radians(90) the vectors are perpendicular to the projection plane. We can use this to randomly scatter lines that are perfectly flat on the ground but point in different directions:

// Before a Copy to Points SOP
@N = sample_direction_cone({0, 1, 0}, radians(90), set(1, rand(@ptnum)));

Sample Direction Cone3.jpg|400

Sample Hypersphere Uniform

Sample Hypersphere Uniform

This is a quick way to randomly rotate a bunch of girls around in a Copy to Points e.g. get a random @orient.

@orient = sample_hypersphere_uniform(rand(@ptnum));

Sample Hypersphere Uniform.jpg|400

VEX Snippets


//random number, linear spread

//particle age -> Ease in - Ease out
parm*=smooth(ch("start"), ch("end"),@nage); 

//parameter change in a certain time range
parm=fit(@Frame, ch("start"), ch("end"), ch("start_value"), ch("end_value"));

//connect params
parm=fit(@P.y, ch("low"), ch("high"), ch("low_value"), ch("high_value"));

//param from age by multiplier

//param from a particle speed
parm=fit(length(@v),ch("speedmin"),ch("speedmax"), ch("valuemin"), ch("valuemax"));