The one-pager: bindings, syntax, and the functions that carry daily wrangle work. When you need the long version, the 950-snippet library is one search away.
| Binding | Meaning |
|---|---|
@P @N @Cd @uv | position - normal - color - uv (known types, auto-cast) |
@ptnum / @numpt | this point's index / point count |
@primnum / @numprim | same, for primitives |
@Frame @Time | current frame / seconds |
f@mask v@dir i@id s@name | declare your own: float, vector, int, string |
v@opinput1_P | read attr from input 1 at same index |
Gotcha: undeclared custom attrs default to float - @mask works, @dir without v silently truncates to one float. Declare types. |
| A wrangle runs your code once per element (point/prim/vertex) - or once total in Detail mode. |
Read any point, write only yourself - writes to other elements need setpointattrib() (applied after the pass) or a Detail wrangle. |
| Same model as pixel shaders: no loops over the whole mesh, no ordering guarantees. Parallel by default is why it's fast. |
| Function | Gives you |
|---|---|
nearpoint(1, @P) | closest point number on input 1 |
xyzdist(1, @P, prim, uv) | distance to a surface + where (prim,uv) |
primuv(1, "attr", prim, uv) | read any attr at that surface spot |
intersect(1, org, dir, p, u, v) | raycast; -1 = miss |
The transfer/snap/raycast trinity: xyzdist finds where, primuv reads what's there. Half the library builds on these. |
int pt = addpoint(0, pos); |
addprim(0, "polyline", a, b); |
setpointattrib(0, "Cd", pt, {1,0,0}); |
removepoint(0, @ptnum); - delete self (the code form of a delete-by-expression) |
| Gotcha: geometry created in a wrangle appears after the pass; you can't read it in the same wrangle. |
rand(@ptnum) - 0-1, stable per point (add a seed: rand(@ptnum + ch("seed"))) |
noise(@P * freq) - value noise, ~0-1, blobby |
curlnoise(@P) - divergence-free vector - instant swirl |
fit(noise(@P*f), 0.3, 0.7, 0, 1) - the contrast trick: raw noise huddles mid-range; fit stretches it |
fit(v, 0,1, a,b) - clamp - lerp - the math sheet family, VEX spelling |
ch("name") - makes a UI slider (click the button to create it) - art-directability in one call |
chramp("r", x) - a whole artist-editable curve as a function |
sprintf("piece_%03d", i) - naming with padding |
if (@P.y < ch("cut")) removepoint(0, @ptnum); - the idiom to memorize |
i@group_top = @N.y > 0.7; - create/assign by rule |
| Run a wrangle over a group: the Group field on the node - cheaper than an if around everything |
inpointgroup(0, "top", @ptnum) - membership test in code |
Integer division: 1/2 == 0 - write 1.0/2 |
@N doesn't exist unless something created it - Normal SOP first, or @N = normalize(@P - centroid)-style yourself |
String compare is == (fine!), but attribute names are case-sensitive: @cd != @Cd |
| Point wrangle can't change point count reads mid-pass - see create & destroy card |
Degrees vs radians: VEX trig is radians - radians(ch("angle")) for slider-friendly degrees |
Learning rather than referencing? Start with the VEX guide, then search the library as problems arise - it's organized for exactly that motion.