Wood & marble
Periodic bands or rings, bent by noise so they wander like grain and veins.
Cards
One live example to tweak, learn and copy.
How it works
Wood, marble and agate look nothing alike, but a shader builds all three the same way: a pattern that repeats along
one direction, pushed back and forth by 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. 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.
Two kinds of repetition
- Rings repeat with the distance from an axis:
fract(length(p.xz) * density)restarts every1 / densityunits outward from the y axis, which is the polar idea of measuring by distance from a center. That is a tree’s growth rings: one ring per year around the trunk. - Bands repeat along a coordinate:
sin(p.x * frequency)makes parallel stripes, the layers of sediment in sandstone or the veins in marble before they are bent.
The repeat’s shape decides the material. fract gives a sawtooth, light at one end of each repeat and dark at the
other, which matches wood: each year’s ring starts pale in spring and darkens until growth stops. sin gives soft,
symmetric bands. Running either through a power or smoothstep sharpens or softens the edge.
Bending it
Add noise to the value before it repeats, fract((radius + noise(p) * strength) * density), and every ring is pushed
in or out a little, by an amount that changes smoothly from place to place. Neighbouring rings move together, because
the noise at nearby points is similar, so the rings wobble without crossing. That single change takes the pattern from
a target to a log.
How much detail the push carries is the difference between the materials. Wood needs only one octave of
gradient noise, stretched along the trunk so the rings wander slowly up the tree. Marble needs
many: its veins are folded at every scale, so the push is fBmOne layer of noise in a fractal sum. Each octave usually has twice the frequency and half the amplitude of the one before, adding finer and fainter detail. Octave One layer of noise in a fractal sum. Each octave usually has twice the frequency and half the amplitude of the one before, adding finer and fainter detail.fbm(p) = Σ gainᵏ · noise(lacunarityᵏ · p)1.0 - abs(sin(x)).
On a mesh
Feed the pattern the surface’s world or object position instead of its UVsA 2D position on a surface or the screen, usually from 0 to 1 on both axes. Shaders draw shapes and patterns as functions of it. UV coordinates A 2D position on a surface or the screen, usually from 0 to 1 on both axes. Shaders draw shapes and patterns as functions of it.uv = gl_FragCoord.xy / resolution
Further reading
- Fractal Brownian Motion (opens in a new tab)Book
- fBM (opens in a new tab)Article
- Fractional Brownian motion (opens in a new tab)Reference
- Improving Noise (opens in a new tab)Paper
- Perlin noise (opens in a new tab)Reference
- Simplex noise (opens in a new tab)Reference
- sin (opens in a new tab)Reference
- Sine wave (opens in a new tab)Reference
- Shaping functions (opens in a new tab)Book
- atan (opens in a new tab)Reference
- Polar coordinate system (opens in a new tab)Reference
- Shapes (opens in a new tab)Book
- Wood (opens in a new tab)Reference
- MurmurHash (opens in a new tab)Reference
- Hash Functions for GPU Rendering (opens in a new tab)Paper
- Wave Texture Node (opens in a new tab)Docs
- NoiseTexture3D (opens in a new tab)Reference
- length (opens in a new tab)Reference
- fract (opens in a new tab)Reference
- pow (opens in a new tab)Reference
- mix (opens in a new tab)Reference