// Structural family: a flight through mountains. A real perspective camera // travelling forward over a raymarched heightfield — peaks rise, pass to either // side and occlude what is behind them, with a snowline near the top and the // ridge silhouettes drawn in the song's hand. // // Ridge Terrain is the neighbour, and it is the flat version of this: parallax // bands of 1D noise that slide sideways and can never hide each other, because // there is no depth for them to hide in. Here the image is a 3D field sampled // along the ray, so the motion is INTO the frame rather than across it, valleys // open and close as the camera passes through them, and a near peak eats a far // one. The massifs themselves are the song's protagonist, extruded: a hollow // cast makes calderas, a notched one makes star-shaped ridges. export const mountainFlight = { name: 'Mountain Flight', family: 'structural', kind: 'fragment', // Personality: see look/Personality.js. Identity: see look/Identity.js. consumes: ['cast', 'ink', 'staging'], traits: ['camera', 'space', 'style'], params: { relief: { type: 'float', range: [0.15, 1.4], default: 0.55, uniform: 'u_relief', bias: 'energy' }, rugged: { type: 'float', range: [0.15, 1.1], default: 0.45, uniform: 'u_rug', bias: 'density' }, ridges: { type: 'int', range: [2, 5], default: 4, uniform: 'u_oct', bias: 'density' }, massif: { type: 'float', range: [0.1, 0.9], default: 0.5, uniform: 'u_massif' }, span: { type: 'float', range: [4, 16], default: 8.0, uniform: 'u_span', bias: 'density' }, altitude: { type: 'float', range: [0.15, 2.2], default: 0.7, uniform: 'u_alt', slowAxis: true }, snowline: { type: 'float', range: [0.15, 1.1], default: 0.55, uniform: 'u_snow', bias: 'energy' }, speed: { type: 'float', range: [0.1, 2.5], default: 0.8, uniform: 'u_speed', bias: 'motion', rate: true }, palette: { type: 'palette', count: 6 }, }, reactive: { relief: { feature: 'bandLow', amount: 0.22, response: 'smooth' }, snowline: { feature: 'bandHigh', amount: 0.2, response: 'smooth' }, altitude: { feature: 'bandSub', amount: 0.15, response: 'smooth' }, }, shader: ` // The massif standing in the world cell around w: the song's protagonist, used // as a PLAN rather than a picture — its footprint is extruded into a mountain. // Kept strictly inside its own cell so one sample of one cell is the whole // answer, which is what makes it affordable inside the march. float massifH(vec2 w) { vec2 cell = floor(w / u_span); vec2 local = w - (cell + 0.5) * u_span; // Which node of the song's lattice this cell got, and how big it stands. vec3 node = stageNode(floor(hash12(cell) * 7.0), 8.0); vec2 at = clamp(node.xy, -1.0, 1.0) * u_span * 0.18; float s = u_span * 0.2 * clamp(u_massif * node.z, 0.08, 1.1); float d = castMain((local - at) / s) * s; // Flanks fall away from the footprint's edge; the summit is its middle. float m = sat(-d / max(s * 0.9, 1e-3)); return pow(m, 0.7) * u_relief * 1.7; } float terrainH(vec2 w) { // The song's element size is the size of the whole landscape's vocabulary: // a few enormous massifs, or a crowd of small ones. vec2 q = w * u_rug / max(stageScale(), 0.25); float sum = 0.0, norm = 0.0, amp = 1.0; for (int i = 0; i < 5; i++) { if (i >= u_oct) break; // Ridged, not billowy: mountains have crests. float n = 1.0 - abs(vnoise(q) * 2.0 - 1.0); sum += n * n * amp; norm += amp; q = rot(0.63) * q * 2.03; amp *= 0.45; } return (sum / max(norm, 1e-3)) * u_relief + massifH(w); } vec4 scene(vec2 uv, vec2 p) { float t = u_time * u_speed + u_seed; p = sigCamera(p); // The camera rides a fixed height over whatever it is flying across, so a // tall massif lifts the flight path instead of swallowing it. vec3 ro = vec3(u_seed * 3.7, 0.0, t * 4.0); ro.y = terrainH(ro.xz) + u_alt * (1.0 + stageScale() * 0.3); // The track's horizon decides how far down the camera is looking. vec3 rd = normalize(vec3(p.x, p.y - sigHorizonY() * 0.5, 1.6)); float dist = 0.4; float hit = 0.0; float gap = 0.0; float grazed = 1e3; // closest the ray came, per unit distance // A march ends on its hit or its far plane, not on a param. // lint: fixed-cost for (int i = 0; i < 72; i++) { vec3 at = ro + rd * dist; gap = at.y - terrainH(at.xz); grazed = min(grazed, gap / max(dist, 1.0)); if (gap < 0.002 * dist) { hit = 1.0; break; } // Cone stepping: safe near the surface, cheap out at the far end. dist += max(gap * 0.5, 0.03 + dist * 0.02); if (dist > 46.0) break; } float fog = sat(dist / 46.0); vec3 col; if (hit > 0.5) { vec3 at = ro + rd * dist; float e = 0.02 + dist * 0.006; vec3 nrm = normalize(vec3( terrainH(at.xz - vec2(e, 0.0)) - terrainH(at.xz + vec2(e, 0.0)), 2.0 * e, terrainH(at.xz - vec2(0.0, e)) - terrainH(at.xz + vec2(0.0, e)))); vec3 sun = normalize(vec3(0.55, 0.42, -0.5)); float diff = sat(dot(nrm, sun)); float elev = sat(at.y / max(u_relief * 2.2, 0.2)); // Snow lies high, and only where the slope will hold it. float snow = smoothstep(u_snow, u_snow + 0.16, elev * (0.45 + 0.75 * nrm.y)); vec3 rock = mix(pal(2), pal(3), sat(elev * 1.3)); col = mix(rock, pal(5), snow); col *= 0.22 + 0.9 * diff; col += pal(1) * 0.12 * sat(nrm.y); // sky bounce into the flats } else { col = mix(pal(1) * 0.45, pal(0) * 0.22, sat(rd.y * 2.2 + 0.15)); fog = 0.85; // The ridgeline the sky is cut against, drawn at the song's weight. col += pal(4) * inkStroke(grazed * 0.6) * 0.5; } col = sigAir(col, p, fog); return vec4(inkValue(col), 1.0); } `, }; export default mountainFlight;