Value noise
Put a random value at every grid corner and blend between them, for smooth randomness that varies across space.
How it works
A hashA function that scrambles its input into a value that looks random but is always the same for the same input. Shaders use it for per-pixel and per-cell randomness. Hash A function that scrambles its input into a value that looks random but is always the same for the same input. Shaders use it for per-pixel and per-cell randomness. Noise A smooth pseudo-random function of position. Random values or gradients sit on a grid and are blended in between, so nearby points get similar values and the result has no visible pattern.h = fract(sin(dot(p, k)) × big) gives each input an unrelated value, so neighboring pixels jump from dark to light at
random. Most natural things are not like that: a cloud, a stain or a rock surface varies smoothly from point to point
and only looks random at a larger scale. NoiseA smooth pseudo-random function of position. Random values or gradients sit on a grid and are blended in between, so nearby points get similar values and the result has no visible pattern.
Corners and blending
Split the position into a cell and a position inside it, the same floor and fract split used for tiling. Each of
the cell’s four corners gets a random value from the hash. The pixel’s value is a blend of the four, weighted by how
close it is to each:
float valueNoise(vec2 p) {
vec2 i = floor(p); // the cell's bottom-left corner
vec2 f = fract(p); // where the pixel is inside the cell, 0..1
float a = hash21(i); // bottom left
float b = hash21(i + vec2(1.0, 0.0)); // bottom right
float c = hash21(i + vec2(0.0, 1.0)); // top left
float d = hash21(i + vec2(1.0, 1.0)); // top right
vec2 u = f * f * (3.0 - 2.0 * f); // smoothstep fade, per axis
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}
The two inner Linear interpolation (mix) Blends from a to b by a factor t, along a straight line. GLSL calls it mix; HLSL and most node editors call it lerp.mix calls blend along x on the bottom and top edges, and the outer one blends those two results
along y. This is bilinear interpolation, built from mixBlends from a to b by a factor t, along a straight line. GLSL calls it mix; HLSL and most node editors call it lerp.mix(a, b, t) = a (1 − t) + b thash21 is the sine hash from the
hash fundamental; any hash that maps a cell to 0..1 works. Neighboring cells share their corners, so the result is
continuous across cell borders: a pixel on the border gets the same two corner values from either side.
The scale of p sets the size of the features. valueNoise(uv * 8.0) has about eight blobs across the screen;
uv * 40.0 makes it fine grained.
Why the fade curve
Blending with Smoothstep A soft threshold. It is 0 below the first edge, 1 above the second, and follows an S-shaped curve with flat ends in between.f directly is linear interpolation. It is continuous, but its slope jumps at every cell border, and
the eye picks up those creases as a faint grid of straight lines and diamond shapes. Passing f through
f * f * (3.0 - 2.0 * f) first, the same cubic that smoothstepA soft threshold. It is 0 below the first edge, 1 above the second, and follows an S-shaped curve with flat ends in between.t = clamp((x − e0) / (e1 − e0), 0, 1); s = t² (3 − 2t)
The cubic’s second derivative still jumps at the borders. That is invisible in a flat color, but it shows once the noise is used as a height and lit, because lighting depends on the slope and the slope’s rate of change. The quintic fade fixes that, at a couple more multiplications:
vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0); // 6f⁵ − 15f⁴ + 10f³
Use the cubic for colors and masks, and the quintic when the noise becomes geometry or a normal.
What it looks like, and its limits
Value noise ranges from 0 to 1, though values near the ends are rare because they need four corners near the same end. It looks soft and slightly blocky: the bright and dark spots sit on the grid corners, and if you look for it you can see the grid’s alignment. That is acceptable for a dissolve mask, a flicker or anything that moves, and it is the cheapest noise there is: four hashes and three mixes.
When the grid shows, the usual fix is gradient noise, the next fundamental, which hides the lattice better for a little more math. Adding several scaled copies of either noise gives the richer detail of fBm.
Using it
Noise is a value from 0 to 1, so it plugs into everything from the shaping fundamentals. Threshold it with
smoothstep for blotches, compare it with a moving value for a reveal, or mix two colors with it:
float n = valueNoise(uv * 6.0);
// a soft edge that sweeps across as progress rises
float mask = smoothstep(progress - 0.05, progress + 0.05, n);
vec3 color = mix(vec3(0.1, 0.3, 0.1), vec3(0.4, 0.6, 0.2), n);
Animate it by moving the input (uv * 6.0 + vec2(time * 0.2, 0.0) scrolls it), or by blending between two noise
fields over time. Adding time to only one axis of a 2D noise just slides the pattern; for noise that changes in place
you need a 3D noise with time as the third axis, which works the same way with eight corners instead of four.