This browser has no WebGPU, so the sketch cannot run here. The program is below, and it runs in a current Chrome, Edge or Safari.

Wandering Terrain

apply formation position correction for smooth motion of a terrain model

Open in new tab ↗ · animationlattnoiseterrain

////////////////////////////////////////////////////
// wandering-terrain
// apply formation position correction for smooth motion 
// of a terrain model
// concept derived from devmar's Godot tutorial
// https://www.youtube.com/watch?v=rcsIMlet7Fw
///////////////////////////////////////////////////

&sz = 64;
&texel = div(2,&sz);

&freq = 4;
&scl = 4;

&speedx = 0.0004;
&speedy = -0.0004;
&speedz = 0.001;

// continuous signed-domain drift
&posxy = mlt(#terra.step,(&speedx,&speedy,0));

// snapped sampling offset:
// convert continuous drift into whole texel steps,
// then scale into noise domain frequency
&texelIdx = dom_idx(&posxy, &texel);
&snap = mlt(&texelIdx, &texel, &freq);

// residual sub-texel phase:
// this is the amount the visible formation 
// moves to hide the discrete sampling jump
&texelPhs = dom_phs(&posxy, &texel);


&noiseCoord = 
add( 
   mlt(C,&freq),
   (
      &snap.x,
      &snap.y,
      mlt(step,&speedz)
   )
);



#terra{
   dim = (&sz,&sz,1);
   // 3D perlin noise
   run = LATT.CUBE.QUINTIC[&noiseCoord]{
      dot(nrm(R),D)
   }; 
}


~terra{
   dim = (&sz,&sz,1);

   // move the rendered formation by the opposite residual phase,
   // so the terrain appears to drift continuously even though
   // the sampled noise field only updates on texel-sized jumps
   pos = mlt(&scl, -&texelPhs).xzy;

   col = #colormap[ add(#terra, 0.5) ]; 
   disp = add(C, (0,0,#terra));

   scl = (&scl,&scl,1);
   rot = (HALF_PI,0,0); 
   filter = INTERP;
}


^cam{
   light = (1);
   fill = (0.25);
}


// the color map is a stochastic 1D color ramp 
// the heightmap values are mapped to color values along the ramp
// created with a random value and continuously blurred
#colormap{
   dim = (32,1,1);
   set = rand(1,2,3);
   run = div( add(#, #(-1,0),#(1,0)), 3 );
}

// blur runs for only 3 steps
@mapBlur(step == 3){
   stop(#colormap);
}