Course outline
Noise and Shaping Functions
In one line
Noise is random numbers made smooth: hash a grid, blend the corners (value noise), add smaller copies (fBm). Shaping functions bend a number's curve. Together they make clouds, rust, and the paint's metal flake.
Think of it like this
A sheet of rough paper under your finger is random, but not jumpy: each bump leans gently into the next. White-noise TV static is jumpy. Noise functions give you the paper, not the static.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- hash
- A function that turns a position into a repeatable pseudo-random number.
- value noise
- Hashed numbers on a grid, blended smoothly between grid points.
- fBm
- Fractal Brownian motion: several layers of noise, each twice as detailed and half as strong, added together.
- octave
- One layer in an fBm sum.
- shaping function
- A function such as
poworsmoothstepthat reshapes a number's range without changing its limits.
Step by step
01Measure three noises
The first example draws hash, value noise and fBm into a 32 × 32 float picture each and prints min, max, mean and the biggest jump between neighbouring pixels. Hash jumps by 0.899; value noise by only 0.164: that is what smooth means.
02Watch octaves add up
One octave of fBm has a maximum of 0.5 (the first amplitude). Five octaves can reach 0.97, and their mean moves to 0.57.
03The negative bug
The last lines print floor and int for four x values. They agree for positive x and differ for the negative ones: cell 0 would cover -1 to 1.
04Flakes on a ball
The second example is the paint's idea on a sphere: a hash of the object-space cell, turned into a tilt, then a specular highlight. The ball turns, the flakes are fixed to it and glint in turn.
Try it yourself
- 1
Fewer flakes
Change
uScalefrom40to15in the ball example. The cubes are 6.7 cm wide, so the flakes become larger, like glitter. Smaller cells give more, finer flakes. - 2
Octaves
Change
fbm(uv, 5)tofbm(uv, 1)in the on-screen shader. The right third becomes as smooth as the middle one, just dimmer.
Code & diagrams
Left: hash. Middle: value noise. Right: fBm with 5 octaves. The text lines come from 32 × 32 float pictures.
Console
Run the scene to see its console.Expected console output
hash noise: min 0.00 max 0.97 mean 0.61 | biggest step between neighbouring pixels 0.899
value noise: min 0.02 max 0.99 mean 0.62 | biggest step between neighbouring pixels 0.164
fbm, 1 octave: min 0.01 max 0.49 mean 0.31
fbm, 5 octaves: min 0.10 max 0.82 mean 0.57
x = -1.5 -> floor: -2 | int: -1
x = -0.5 -> floor: -1 | int: 0
x = 0.5 -> floor: 0 | int: 0
x = 1.5 -> floor: 1 | int: 1A plain ShaderMaterial with a hand-written light. The build topic does the same inside a MeshPhysicalMaterial so the scene's lights apply.
Console
Run the scene to see its console.Expected console output
shaders: 1 | draw calls: 1Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
A hash that uses sin on huge numbers
In your own shader, hash each pixel of a 32 × 32 picture with fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453) and compare p = pixel with p = pixel * 100000.0.
Myth vs fact
Myth
A shader can call random().
Fact
GLSL has no random function. What looks random is always a function of position (and time), which is why the same pixel gives the same value every frame.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
fBm is often given a
lacunarity(the frequency multiplier, 2.0 here) and again(the amplitude multiplier, 0.5). 2.0 and 0.5 give the classic look;gain0.7 gives rougher noise. - ▸
Rotating or offsetting each octave a little hides the grid directions that value noise shows. A cheaper trick is to use a different cell offset per octave.
Remember this
- 1
The problem this solves: a shader has no
random(). Every pixel runs the same code, and the same input must give the same output (or a pattern would flicker between frames). You need a function that looks random but is a fixed rule, and that is smooth where you want smoothness. - 2
Hash. A hash turns a position into a repeatable number from 0 to 1 with a few multiplications and
fractcalls. The same cell always gives the same number. Hash alone is static: neighbouring cells are unrelated (the first panel on screen). - 3
Value noise. Hash the four corners of the cell a point is in, then blend them with
mix, using a smoothed fractionf * f * (3.0 - 2.0 * f)so there are no creases at cell edges (the middle panel). fBm (fractal Brownian motion) adds copies of value noise, each twice as detailed (p *= 2.0) and half as strong (amplitude *= 0.5): big clouds plus small clouds plus tiny grain (the right panel). More octaves cost more: every octave is another noise call per pixel. - 4
Simplex and gradient noise are smoother and have fewer grid artefacts than value noise, but need more code. three.js ships a CPU
SimplexNoise(three/addons/math/SimplexNoise.js) for building geometry in JavaScript; for shaders, copy a well-known GLSL implementation with its licence. Value noise is enough for this course. - 5
Shaping functions bend a 0 to 1 number:
pow(x, 2.0)pushes values down (more dark),sqrtpulls them up,smoothstepmakes an S-curve,sinrepeats. The curve you apply after noise decides the look:pow(noise, 3.0)makes rare bright spots out of smooth cloud. - 6
Metal flake is a hash used as a surface tilt. Cut space into small cubes with
floor(position * scale), hash each cube to a random direction, and tilt the normal by it. Flakes whose tilt faces the light and the eye sparkle. They must be computed from object space, so they stay on the bike when it turns. - 7
Edge cases.
int()cuts towards zero butfloor()goes down, so noise built onint()has a double-wide cell around 0 (the first example prints it). Hashes built onsin(big number)lose their randomness when positions get huge, because float precision runs out; the hash here uses onlyfractand multiplications.
Explain it without notes
Why is value noise smooth when hash noise is not?
Why compute flakes in object space instead of screen or world space?
Practice
Make fBm with 3 octaves and a gain of 0.7.
Turn the value noise into rust: dark brown where the noise is above 0.6.
Done when you can
Build value noise from a hash
Add octaves to make fBm and say what each costs
Explain why
int()is wrong for cellsSay why flakes use object space