LATT

Lattice-sampling and gradient noise interpolation

LATT is Utomata's lattice-sampling construct. Given a coordinate, it evaluates an expression at the lattice points surrounding that coordinate and interpolates the results into a single value.

The lattice itself stores nothing. It has no dimensions, no persistent values, and no state of its own: its points are generated implicitly from the coordinate being evaluated, and the body expression runs only at the points required for that sample. This is what distinguishes LATT from Utomata's other sampling constructs. A field lookup retrieves data already stored in a field; a reducer visits and combines stored field cells; LATT generates its sampling points procedurally and requires no stored data at all.

Its main use is constructing procedural functions — value noise, gradient noise, and structures built from them — directly in an expression, without first building a field to contain them.

Definition

The general syntax is:

LATT.GEOMETRY.BLEND[coordinate]{
  expression
}

The geometry determines which lattice points surround the evaluation position, the body expression determines what each of those points contributes, and the blend determines how the contributions are interpolated into the final value.

The coordinate expression defines a position in lattice space. It is independent of field resolution and need not correspond directly to C. Scaling it changes the frequency of the resulting pattern; offsetting it moves through the lattice. There is no separate frequency property — the scale and movement of the coordinate expression are the scale and movement of the lattice:

&coord = mlt(C, 8);

LATT.RECT[&coord]{
  R
}

The coordinate expression and the body are required. Geometry and blend are optional and default to RECT and QUINTIC, so LATT[coordinate]{ expression } is shorthand for LATT.RECT.QUINTIC[coordinate]{ expression }. A blend can only be named after a geometry — LATT.QUINTIC[C]{ R } is invalid, because the blend would occupy the geometry position.

Lattice Built-ins

Three values are available inside the lattice body, and only there:

Name Role Description
P Position coordinate of the current lattice point
D Displacement vector from the current lattice point to the evaluation position
R Random value deterministic random vector associated with the current lattice point

P is the integer lattice position currently being visited. Although represented as a vector value, its active components correspond to integer coordinates in lattice space.

D is the displacement from that lattice point to the position being sampled:

D = coordinate - P

Its direction points from the lattice point toward the evaluation position.

R is a deterministic random three-component value in the range -1 to 1, belonging to the lattice point itself. Sampling the same lattice point under the same project seed always yields the same R. A lattice does not generate new randomness on every step; procedural patterns animate only when their input coordinates move.

These three primitives are enough to construct the classic procedural noises.

Value noise uses R directly — each lattice point contributes its random value, and the blend interpolates between them:

&noise = LATT.RECT.QUINTIC[mlt(C, 8)]{
  R
};

2D Perlin noise treats R only as a direction and compares it to the displacement:

&noise = LATT.RECT.QUINTIC[mlt(C, 8)]{
  dot(nrm(R), D)
};

The lattice machinery is identical in both cases; only the contribution computed at each point changes. LATT is not any particular noise algorithm — it provides the spatial structure, the deterministic randomness, and the interpolation, and the body determines the function being constructed.

Geometries

The geometry determines which points surround the evaluation position, and therefore how many times the body is evaluated per sample. Utomata currently provides two.

RECT

RECT, the default, is a two-dimensional rectangular lattice. Each evaluation uses the four corners of the lattice cell containing the sample position:

P ───── P
│       │
│   x   │
│       │
P ───── P

The four body results are interpolated first along x, then along y.

Because RECT is two-dimensional, lattice-point positions use x and y while P.z remains 0. One consequence is worth noting: D is still calculated from the complete three-component input coordinate, so any non-zero z in the coordinate remains present in D.z. For ordinary 2D coordinates this makes no difference, but it matters when constructing animated coordinates. To animate a RECT lattice, move its x or y coordinates and leave z at zero:

&time = mlt(step, 0.01);
&coord = add(mlt(C, 4), (0, &time, 0));

&noise = LATT.RECT[&coord]{
  dot(nrm(R), D)
};

If z should act as a genuine third lattice dimension, use CUBE.

CUBE

CUBE extends the same model into three dimensions. Each evaluation uses the eight corners of the cubic lattice cell surrounding the coordinate, interpolated along x, y, and z.

CUBE describes the dimensionality of the lattice, not of the field or formation in which it appears. A 2D field can sample a 3D lattice:

&time = mlt(step, 0.01);

&noise = LATT.CUBE.QUINTIC[
  (mlt(C.x, 4), mlt(C.y, 4), &time)
]{
  dot(nrm(R), D)
};

Here x and y come from the field coordinates while z moves through the lattice over time: the field remains two-dimensional, but each frame samples a different 2D cross-section of a three-dimensional procedural function. The same construct works inside a true 3D field, where all three components of C vary spatially.

Geometry Dimensions Samples per evaluation Interpolation
RECT (default) 2D 4 bilinear
CUBE 3D 8 trilinear

Because the body runs once for every contributing point, geometry also sets the computational cost: CUBE evaluates its body eight times per result, while RECT only needs to evaluate four.

Blend Modes

The blend mode determines how the contributions from the surrounding points change as the evaluation position moves between them. It does not change the geometry or which points are visited — only the interpolation curve.

Blend Interpolation Character
LINEAR t constant rate of transition; lattice boundaries may remain visible
CUBIC 3t² - 2t³ smoothstep; flattens toward each lattice point
QUINTIC (default) 6t⁵ - 15t⁴ + 10t³ smoothest transition, with smooth derivatives across boundaries

With LINEAR, the direction of change shifts abruptly when a sample crosses from one lattice cell into another, which can make the cell structure visible. CUBIC removes the abrupt transitions; QUINTIC additionally smooths the derivatives, which is particularly valuable for gradient noise, where discontinuities in the interpolation curve would otherwise expose the rectangular or cubic structure of the underlying lattice. This is why QUINTIC is the default.

Composing Lattices

LATT returns an ordinary Utomata vector value and combines freely with operators, macros, fields, and other expressions. LATT calls can also be called directly in formation properties, bypassing field computation alltogether. A common pattern is to define the lattice as a macro and run it in a field:

&coord = mlt(C, 8);

&noise = LATT.RECT.QUINTIC[&coord]{
  dot(nrm(R), D)
};

#A {
  dim = (256, 256, 1);
  run = &noise;
}

The coordinate expression is the primary control over the resulting pattern. Increasing its scale increases lattice frequency:

LATT.RECT[mlt(C, 4)]{ R }
LATT.RECT[mlt(C, 16)]{ R }

and offsets move through the lattice:

LATT.RECT[add(mlt(C, 8), (0, &time, 0))]{
  R
}

Higher-level procedural structures are built by composing ordinary LATT expressions rather than through dedicated settings. There is no built-in octave or fractal-noise property; a fractal pattern is simply a sum of lattices at different frequencies:

&o1 = LATT.RECT[mlt(C, 4)]{
  dot(nrm(R), D)
};

&o2 = LATT.RECT[mlt(C, 8)]{
  dot(nrm(R), D)
};

&o3 = LATT.RECT[mlt(C, 16)]{
  dot(nrm(R), D)
};

&noise = add(
  &o1,
  mlt(&o2, 0.5),
  mlt(&o3, 0.25)
);

Determinism and Numeric Mode

R is derived deterministically from the integer lattice position and the global project seed. The same lattice expression sampled at the same coordinates therefore produces the same result across evaluations; changing step changes nothing unless step alters the coordinate being sampled. The same project seed governs Utomata's other seeded random behavior, keeping procedural results reproducible from the program and its seed.

LATT operates in floating-point mode only. If a field configured for integer execution contains a lattice expression, the field is evaluated in floating-point mode instead. The restriction applies to the lattice computation itself; LATT is otherwise accepted in field and formation expressions wherever ordinary Utomata expressions are.

Reference

General syntax:

LATT.GEOMETRY.BLEND[coordinate]{
  expression
}

LATT[coordinate]{ expression } is equivalent to LATT.RECT.QUINTIC[coordinate]{ expression }.

Geometry

Name Role Description
RECT (default) geometry 2D rectangular lattice; evaluates four surrounding corners
CUBE geometry 3D cubic lattice; evaluates eight surrounding corners

Blend Modes

Name Role Description
LINEAR blend linear interpolation
CUBIC blend cubic smoothstep interpolation
QUINTIC (default) blend quintic interpolation
SMOOTH alias alias for QUINTIC

Lattice Built-ins

Name Role Description
P coordinate current integer lattice-point position
D displacement vector from P to the evaluation coordinate
R value deterministic random vector at P, in the range -1 to 1