Skip to content
Materials · TechniqueIntermediate

Wood & marble

Periodic bands or rings, bent by noise so they wander like grain and veins.

PositionUVSurface

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 noise. Perfect repetition reads as a printed stripe; the noise is what makes it look grown or formed. Each material then only changes three things: what the repetition is measured along, what shape each repeat has, and how hard the noise pushes.

Two kinds of repetition

  • Rings repeat with the distance from an axis: fract(length(p.xz) * density) restarts every 1 / density units 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 fBm, several octaves summed, and the result is turned into thin dark lines with something like 1.0 - abs(sin(x)).

On a mesh

Feed the pattern the surface’s world or object position instead of its UVs and it becomes solid: the rings run through the volume, so every face of the mesh shows the cut you would see in a carved block, end grain on the faces across the trunk and long stripes along it, with no seams and no unwrapping. With UVs instead, the same code works on a quad, a UI panel or a terrain decal. Blender’s Wave Texture node does this natively, with bands or rings, a sawtooth or sine profile, and noise distortion with its own detail setting; writing it by hand is what lets you shape each ring and port it to engines that have no such node.

Further reading