feat: weave a flowing multicolor palette through the terrain grid

This commit is contained in:
2026-09-05 12:36:34 +03:00
parent 51a9c743da
commit 43e510341e

View File

@@ -84,6 +84,19 @@ export function createTerrain(
varying float vDepthFade;
varying float vFlow;
varying vec3 vTerrainPosition;
varying vec3 vGridColor;
// A closed palette ribbon: its ends meet in cyan so travel never
// produces a color seam. Compute it per vertex, not per pixel.
vec3 gridSpectrum(float phase) {
float p = fract(phase);
vec3 cyan = vec3(0.025, 0.70, 0.90);
vec3 color = mix(cyan, vec3(0.075, 0.18, 0.80), smoothstep(0.04, 0.22, p));
color = mix(color, vec3(0.39, 0.085, 0.80), smoothstep(0.22, 0.40, p));
color = mix(color, vec3(0.88, 0.035, 0.28), smoothstep(0.40, 0.60, p));
color = mix(color, vec3(0.95, 0.21, 0.08), smoothstep(0.60, 0.78, p));
return mix(color, cyan, smoothstep(0.78, 1.0, p));
}
float hash21(vec2 point) {
point = mod(point, 256.0);
@@ -127,6 +140,12 @@ export function createTerrain(
vHeight = clamp(height / max(1.0, uRelief), 0.0, 1.0);
vRoadMask = roadMask;
// Signed lateral variation gives each bank its own color rhythm.
// Whole longitudinal cycles preserve the existing terrain wrap.
float chroma = world.y * ${(31 / NOISE_PERIOD).toFixed(10)}
+ position.x * 0.014 + height * 0.025
+ 0.12 * sin(world.y * ${((Math.PI * 2 * 17) / NOISE_PERIOD).toFixed(10)} + position.x * 0.028);
vGridColor = gridSpectrum(chroma);
vec4 viewPosition = modelViewMatrix * vec4(displaced, 1.0);
float viewDistance = -viewPosition.z;
vDepthFade = smoothstep(4.0, 18.0, viewDistance)
@@ -148,13 +167,15 @@ export function createTerrain(
varying float vDepthFade;
varying float vFlow;
varying vec3 vTerrainPosition;
varying vec3 vGridColor;
void main() {
float ridgeMix = smoothstep(0.025, 0.29, vHeight);
vec3 valley = mix(uLowColor, vec3(0.10, 0.64, 1.0), uOverdrive * 0.55);
vec3 crest = mix(vec3(0.7, 0.025, 0.22), vec3(1.0, 0.12, 0.065), uOverdrive * 0.75 + vFlow * 0.18);
vec3 color = mix(valley, mix(vec3(0.28, 0.06, 0.52), crest, ridgeMix), ridgeMix);
color = mix(color, uHighColor, 0.13);
vec3 color = mix(vGridColor, uLowColor, 0.06);
// Speed warms passing accents, while the full palette stays present.
float hotAccent = uOverdrive * smoothstep(0.62, 1.0, vFlow) * 0.36;
color = mix(color, vec3(1.0, 0.28, 0.10), hotAccent);
color = mix(color, uHighColor, ridgeMix * 0.055);
color = mix(color, mix(uFogColor, uHazeColor, 0.2), 1.0 - vDepthFade);
float pulse = 0.88 + 0.12 * smoothstep(0.16, 0.55, vFlow);
float routeCalm = mix(1.0, 0.9, smoothstep(0.82, 1.0, uRouteProgress));