Houdini Vex Reference
Declaring attributes
f@name //float
u@name //vector2 (2 floats)
v@name //vector3 (3 floats)
p@name //vector4 (4 floats)
i@name //int
2@name //matrix2(2x2 floats)
3@name //matrix 3 (3x3 floats)
4@name //matrix (4x4 floats)
s@name //string
d@name //dict
s[]@name //array of strings
f[]@name //array of floats
This is another way to define them. A drawback to this method is there can be no evaluation on the right side of the equation.
float @mass = 1;
vector @up = {0, 1, 0};
The typical way to grab an attribute from the second input of a wrangle would be to use the point
function. Another way is to use @opinput1_
followed by the attribute name. This will grab the element with the same index as the first input. There is also a “attribute to match” parameter that will let you use arbitrary attributes such as id
.
v@cord_offset = point(1, "P", 0);
v@cord_offset = @opinput1_P;
Reference Parameters in Vex
ch('flt1'); // Float
chf('flt2'); // Float
chi('int'); // Integer
chu('vector2') // Vector 2
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
Global Variables
@Time //Float time ($T)
@Frame //Float frame ($FF)
@SimTime //Float simulation time ($ST), only present in DOP contexts.
@SimFrame //Float simulation frame ($SF), only present in DOP contexts.
@TimeInc //Float time step (1/$FPS)
Attribute Wrangle Variables
v@P //The position of the current element.
i@ptnum //The point number attached to the currently processed element.
i@numpt //The total number of points in the geometry.
i@vtxnum //The linear number of the currently processed vertex.
i@numvtx //Vertices in the primitive of the currently processed element.
i@primnum //The primitive number attached to the currently processed element.
i@numprim //The total number of primitives in the geometry.
i@elemnum //The index number of the currently processed element.
i@numelem //The total number of elements being processed.
Arrays
int nbors[] = neighbours(0, @ptnum);
i[]@connected_pts = neighbours(0, @ptnum);
Set Attribute as a Vector that Houdini Should Transform
By default, when you declare a vector attribute in Houdini it doesn’t know if it should transform it with the rest of the geo or not. Some attributes, like @orient
, @v
, and @N
, Houdini automatically knows to transform. If you create your own attribute, you’ll have to set the type info explicitly. I’m curious if that attribute type info is visible somewhere.
v@attribute1 = 1;
setattribtypeinfo(0, “point”, “attribute1”, “vector”);
addvariablename(0, “attribute1”, “ATTRIBUTE1”);
You can also specify the type with the attributeadjustvector
node.
Create Groups from Attributes
This is of limited usefulness. detailintrinsic
is a handy way to get a list of all the primitive attributes. See more on that here.
string primattribs[] = detailintrinsic(0,"primitiveattributes");
for (int i = 0; i < len(primattribs); i++) {
setprimgroup(0, primattribs[i], @primnum, prim(0, primattribs[i], @primnum), "set");
}
Easy positive or negative integer
i@rand_mag = rand(@ptnum)< 0.5 ? -1 : 1;
Or even easier:
sign(rand(@ptnum)-0.5);
Extract transform from Alembic
From this help page on packedtransform()
.
Hip download.
Negate and store transform:
// get transform from alembic
matrix full_transform = primintrinsic(0, "packedfulltransform", 0);
4@disabled_transform = full_transform;
// invert that transform
matrix invert_full_transform = invert(full_transform);
matrix transform = invert_full_transform;
// get current packed transform
matrix3 primtf = primintrinsic(0, "transform", @primnum);
setprimintrinsic(0, "transform", @primnum, primtf * (matrix3)transform);
// set position
int primpoint = primpoint(0, @primnum, 0);
vector pos = point(0, "P", @ptnum);
setpointattrib(0, "P", @ptnum, pos * transform);
Apply transform to arbitrary geo:
matrix transform = prim(1, "disabled_transform", 0);
// get current packed transform
setprimintrinsic(0, "transform", @primnum, (matrix3)transform);
// set position
int primpoints[] = primpoints(0, @primnum);
for (int i = 0; i < len(primpoints); i ++){
int point_num = primpoints[i];
vector pos = point(0, "P", point_num);
setpointattrib(0, "P", point_num, pos * transform);
}
Find Weighted Average of Near Points Attribute
// Compute color of voxel based on distance weighted
// average Cd of particles within radius of .05
int near_points[] = nearpoints(1, @P, .05);
// Find distances to all near points
float dists[];
foreach(int i; int pt; near_points) {
dists[i] = distance(@P, point(1, "P", pt));
}
// Normalize by maximum distance
float max = max(dists);
float norm_dists[];
foreach (int i; float dist; dists) {
norm_dists[i] = max/dist;
}
// Find weighted average Cd (value)
float total_normalized = sum(norm_dists);
vector value = set(0,0,0);
foreach (int i; float norm_dist; norm_dists) {
float ratio = norm_dist / total_normalized;
value += point(1, "Cd", near_points[i]);
}
value = value / total_normalized;
v@Cd = value;
Modify cracked transform
This stumped me for a while. In order to crack the transform and feed those transform values back into a maketransform, you need to use XFORM_SRT
instead of XFORM_TRS
for the order of the transform.
matrix3 xform = primintrinsic(0, "transform", @primnum);
vector translate, rotate, scale;
cracktransform(XFORM_SRT, XFORM_XYZ, @P, xform, translate, rotate, scale);
matrix3 new_xform = (matrix3)maketransform(XFORM_SRT, XFORM_XYZ, translate, rotate, scale);
3@old_xform = xform;
3@new_xform = new_xform;
Integer to padded string
sprintf('%04d',@Frame)
Simulation Attributes
John Kunz has a great list of attributes used in simulations
Attribute fade along curve
float falloff = chf("falloff");
float offset = chf("offset");
float min = offset * (falloff + 1) - falloff;
float max = min + falloff;
f@value = fit(f@curveu, min, max, 0, 1);
v@Cd = f@value;
Get number from node name
This isn’t vex, but I always forget it.
opdigits('.')
Unique Values
Useful function for finding all the unique values a string or integer attribute has.
int [] uniquevals(<geometry>geometry, string attribclass, string attribute_name)
string [] uniquevals(<geometry>geometry, string attribclass, string attribute_name)
Ternary Conditional
f@density = (f@density>0.01) ? 1.0 : 0.0;
Sample weighted
Modulo Reference
To get a value from 0-1 that loops every 12 frames:
f@cool = (f@Frame / 12) % 1
Normalize attribute sweep between 0 and 1
I find it annoying to have to animate a parameter beyond 1 or below 0, so this lets you have a nice normalized parameter to animate.
0 1
|__________________|
[ ] -> [ ] -> [ ]
Where @mask
goes from 0-1:
float radius = chf("radius");
float offset = chf("offset");
offset = fit(offset, 0, 1, 0, offset + radius);
f@mask = fit(f@mask, offset - radius, offset, 0, 1);
And a version with noise:
float radius = chf("radius");
float offset = chf("offset");
float norm_y = relbbox(0, @P).y;
float noise = (noise(@P*chf("noise_scale")*chv("noise_scale_vector"))-.5)*1;
offset = fit(offset, 0, 1, 0, offset + radius);
float mask = fit(fit(norm_y + noise, 0, 1.75, 0, 1), offset - radius, offset, 0, 1);
Animate point attribute sequentially
When you want only one point or a few points to animate at a time.
float overlap = chf("overlap");
float anim = chf("anim");
float range = (1-overlap) * (npoints(0) + 1)
float pt_range_start = ((1-overlap) * (npoints(0) - 1 - @ptnum));
f@amount = fit(anim, pt_range_start / range, (pt_range_start + 1) / range, 0, 1);
PID POP Controller
vector pid = chv("pid");
v@goal = point(1, "P", idtopoint(1, @ptnum%npoints(1)));
v@error = v@goal - v@P;
v@prev_error = (v@goal - v@pprevious) * @has_pprevious;
v@derivative = (v@error - v@prev_error)/@TimeInc;
v@integral = v@prev_integral + v@error * @TimeInc;
v@force = pid[0] * v@error + pid[1] * v@integral + pid[2] * v@derivative;
v@prev_integral = v@integral;
Links:
Find primitives in a bounding box
int [] primfind(<geometry>geometry, vector min, vector max)