Expression attributes

The @ values read and written inside an Expression. Which ones exist depends on the input.

An Expression runs once per element of whatever is wired into it. An @name is one of those per-element values: a point's position, a pixel's colour, a voxel's density. Read them to make decisions, assign to them to change the result.

// read @Cd, write @P.z: push each point up by its brightness
@P.z = luminance(@Cd) * 100.0;

The input sets the loop

There is no mode to pick. It follows the input, and Automatic conversion covers the conversions between these kinds.

An image cooks as an image and a Volume cooks as a Volume, so a snippet on either one keeps the representation it was given. A distance field has no grid of its own, so it resolves to points, one per grid sample.

The common attributes

Vectors support swizzles, so @P.z, @Cd.rgb and @uv.x all work.

AttributeWhat it isWhere it lives
@PPositionpoints, mesh, volume, distance field
@CdColour (RGBA)points, image
@Cd1, @Cd2, @Cd3The colour at this pixel in the second, third and fourth wired imageimage
@valueThe number itselfnumber array
@NNormal directionpoints, mesh
@pscalePer-element scale / sizepoints
@uvTexture coordinateimage, mesh
@densityVoxel valuevolume
@distDistance to surfacedistance field
@analyticWhich analytic shape this row isanalytic shapes
@dims0, @dims1That shape's dimensions, four numbers eachanalytic shapes
@idStable identity that survives across framespoints, mesh, analytic shapes, splats
@ptnumThe element's index in the loopevery collection
@numptHow many elements the loop runs overevery collection

@dist, @analytic, @dims0, @dims1, @rot and @opacity are columns the data carries and every node downstream can use, but the Expression language does not yet know them by name: a bare read of one is a compile error.

An image Expression takes up to four images. @Cd is the one on the first input and @Cd1, @Cd2 and @Cd3 are the second, third and fourth, which is how a clean plate, a guide image or a displacement map is read alongside the picture being changed. The pins carrying them are labelled input2, input3 and input4, so the number on the pin is always one higher than the number on the attribute. Fed anything other than an image, @Cd1 is an ordinary colour column that the input has to carry under that exact name.

Attributes covers how attributes attach to data across the app.

Reading and writing

Reading is mentioning the attribute. Writing is assigning to it on the left of an =.

@Cd = @P.y > 0 ? {1, 0, 0, 1} : {0, 0, 1, 1};   // read @P, write @Cd
@P += @N * noise(@P * 0.1 + $T) * 5.0;            // read @N and @P, write @P

@ptnum and @numpt come from the loop rather than from a stored column, so they are available on any collection whatever else it carries. Everything else in the table is a column, present only when the input actually has it.

@id can be written, and it is the handle that keeps a point recognisable from one frame to the next. Simulations and effects depend on it, so overwrite it only deliberately.

A swizzled write keeps the rest of the vector. @P.z = ... changes Z alone.

The table above is most of the vocabulary the language knows by name. The rest is @v (velocity), @Alpha, @scale, @orient, @rotation, @weight, @sdf, the simulation pair @age and @life, and the loop stamps @index, @total and @normalized. Any other name has to be written before it is read: @wobble = noise(@P); makes a new attribute and later lines can read it back, but a bare read of a name the snippet never assigned is a compile error.

Reading a column that might not be there

attr_or(default, "name") is the optional read. It gives the column's value where the input carries it and the default where it does not, so a snippet works on data that may or may not have been given a @weight or a @v, and it never demands the column the way a bare @weight does.

@pscale = attr_or(1.0, "weight");
@P += attr_or({0.0, 0.0, 0.0}, "v") * $DT;

The default sets the type, and it has to match the attribute: a scalar default for a scalar column, a vector default for a vector one. A mismatch is a named compile error rather than a silent conversion.

Reading a column the input does not carry is a named error at cook time, listing the attribute and the columns that are available. It is never a silent zero. Match the attribute to the input type from the table above.

See also