Domain repetition is the trick that makes one SDF into a thousand: instead of
drawing many objects, you fold space so the same object appears everywhere. The
standard implementation — lygia’s opRepeat among them — tiles to infinity.
Which is usually what you want in an abstract scene, and exactly what you don’t want when the repetition should visibly stop.
vec3 opRepeat(in vec3 p, in vec3 lima, in vec3 limb, in float s) {
vec3 range = limb - lima;
p = mod(p - lima, range) + lima; // fold p into [lima, limb) first
return mod(p + s * 0.5, s) - s * 0.5;
}
Two folds, in order. The first wraps the point into the bounded region
[lima, limb). The second is the ordinary repetition at spacing s, applied to the
already-bounded coordinate. The result is a finite block of repeated geometry with
nothing outside it.
Usage
float map(vec3 p) {
// a 4x4x4-unit slab of pillars spaced 1 unit apart
vec3 q = opRepeat(p, vec3(-2.0), vec3(2.0), 1.0);
return sdBox(q, vec3(0.2, 1.0, 0.2));
}
Compare to the unbounded version, which fills the entire scene:
vec3 q = mod(p + 0.5, 1.0) - 0.5; // pillars forever, no horizon
Notes
- The bound is a fold, not a clip. Space outside
[lima, limb)wraps back into the region rather than going empty, so you get a repeating block rather than a single isolated one. If you want genuinely empty space beyond the bounds, intersect the result with a box SDF instead. sshould divide evenly intolimb - lima, or the cell at the seam gets cut and you’ll see a visible discontinuity where the outer fold wraps.- Domain repetition breaks the distance guarantee for objects larger than the cell
spacing — a shape wider than
sgets sliced by its neighbors. Keep the SDF comfortably smaller than the cell, or shorten your raymarch step. - Useful for horizons: bound the repetition and the pattern terminates at a distance the camera can actually reach, instead of marching forever into an infinite field.