Skip to content

Modifiers

A modifier is a wrapper around shapes. It transforms the sample point before the distance function runs, or the distance after, in the shape’s own local space — so it moves and rotates with the shape. Every shape carries one mask and one parameter set, so unused modifiers cost nothing.

import { Twist } from '../lib/fabric/modifiers'
<Twist amount={1}>
<Box position={[-3, -3, 0]} size={{ x: 0.4, y: 1, z: 0.4 }} color="#ff8050" material={{ ambient: 0.5, shader: 'lambert' }} />
</Twist>
ComponentOperation
<Onion thickness>abs(d) - thickness — a solid becomes a hollow shell, thickness either side of the surface
<Symmetry axes="xy">p.x = abs(p.x), per listed axis, before evaluation — the positive half mirrored onto the negative
<Twist amount>Rotates the local XZ plane by amount × y — radians per unit of height
<Bend amount>Rotates the local XY plane by amount × x — radians per unit along X
<Displace amount frequency>Adds sin(f·x)·sin(f·y)·sin(f·z) × amount to the distance
<Elongate amount>p − clamp(p, −h, h) — pulls the centre apart by h per axis; a sphere becomes a capsule
<Extrude thickness>Gives a 2D shape a half-thickness along Z
<Revolve radius>Sweeps a 2D shape around +Y at that radius

Extrude and Revolve take a 2D shape into 3D, so they pair with the shapes2d range; without one of them a 2D shape draws as a thin wafer. The props, defaults and a real use of each are in Modifiers reference.

Onion, Symmetry and Elongate preserve the distance metric — the field stays a true signed distance, and raymarching is unaffected.

Twist, Bend and Displace do not. They distort space, so the returned value overestimates how far the ray may safely travel. The march can then step through a surface.

Symptoms are missing or shimmering surfaces at grazing angles. Fixes, in order of preference: reduce the modifier’s magnitude, raise maxSteps, or lower the step relaxation.

Wrappers nest, and each shape ends up with one mask marking which modifiers are active and one set of parameters. The shader applies them in a fixed order — elongate, symmetry, bend, twist, the primitive, then displace and onion — whatever order the JSX nests them in.

<Symmetry axes="x">
<Twist amount={0.8}>
<Box size={{ x: 0.4, y: 1, z: 0.4 }} />
</Twist>
</Symmetry>

A shape with no modifiers takes no branches. Glass shapes take modifiers like any other; the glass options have slots of their own.