feat: charge terrain with acceleration and compact desktop sign staging
This commit is contained in:
@@ -22,6 +22,8 @@ export interface TerrainWorld {
|
||||
routeProgress: number,
|
||||
palette?: Readonly<MutableChapterPalette>,
|
||||
overdrive?: number,
|
||||
surge?: number,
|
||||
spectrumPhase?: number,
|
||||
): void;
|
||||
}
|
||||
|
||||
@@ -54,6 +56,8 @@ export function createTerrain(
|
||||
uFlowDistance: { value: 0 },
|
||||
uSpeed: { value: 0 },
|
||||
uOverdrive: { value: 0 },
|
||||
uSurge: { value: 0 },
|
||||
uSpectrumPhase: { value: 0 },
|
||||
uRouteProgress: { value: 0 },
|
||||
uTerrainEnergy: { value: initialPalette.terrainEnergy },
|
||||
uOctaves: { value: quality.terrainOctaves },
|
||||
@@ -74,6 +78,8 @@ export function createTerrain(
|
||||
uniform float uFlowDistance;
|
||||
uniform float uSpeed;
|
||||
uniform float uOverdrive;
|
||||
uniform float uSurge;
|
||||
uniform float uSpectrumPhase;
|
||||
uniform float uRouteProgress;
|
||||
uniform float uTerrainEnergy;
|
||||
uniform float uOctaves;
|
||||
@@ -85,6 +91,7 @@ export function createTerrain(
|
||||
varying float vFlow;
|
||||
varying vec3 vTerrainPosition;
|
||||
varying vec3 vGridColor;
|
||||
varying float vCrest;
|
||||
|
||||
// A closed palette ribbon: its ends meet in cyan so travel never
|
||||
// produces a color seam. Compute it per vertex, not per pixel.
|
||||
@@ -133,9 +140,17 @@ export function createTerrain(
|
||||
const float S = 0.04495961;
|
||||
vec2 world = vec2(position.x, displaced.z - wrappedPhase);
|
||||
float ridgeNoise = multiOctaveNoise(world * S);
|
||||
// Sharpen and lift the same ridges rather than changing their noise
|
||||
// coordinates. The road remains flat, and the far horizon stays calm.
|
||||
float bank = smoothstep(12.0, 52.0, abs(position.x));
|
||||
float nearRelief = 1.0 - smoothstep(360.0, 680.0, -displaced.z);
|
||||
float energy = (uSurge * 0.52 + uOverdrive * 0.24) * bank * nearRelief;
|
||||
ridgeNoise = mix(ridgeNoise, ridgeNoise * ridgeNoise * 1.8, energy * 0.48);
|
||||
float edgeGrowth = mix(7.0, uRelief, smoothstep(14.0, 150.0, abs(position.x)));
|
||||
float height = roadMask * ridgeNoise * edgeGrowth * uTerrainEnergy;
|
||||
height += roadMask * uOverdrive * (0.7 + 0.7 * sin(world.y * ${((Math.PI * 2 * 34) / NOISE_PERIOD).toFixed(10)} + abs(position.x) * 0.075));
|
||||
float height = roadMask * ridgeNoise * edgeGrowth * uTerrainEnergy * (1.0 + energy);
|
||||
float crest = 0.5 + 0.5 * sin(world.y * ${((Math.PI * 2 * 34) / NOISE_PERIOD).toFixed(10)} + abs(position.x) * 0.075);
|
||||
height += roadMask * bank * nearRelief * crest * crest * (uSurge * 3.8 + uOverdrive * 3.2);
|
||||
vCrest = crest * crest * bank;
|
||||
displaced.y += height + 0.028;
|
||||
vTerrainPosition = displaced;
|
||||
|
||||
@@ -146,7 +161,10 @@ export function createTerrain(
|
||||
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);
|
||||
vec3 cruiseColor = gridSpectrum(chroma + uSpectrumPhase);
|
||||
vec3 speedSpectrum = gridSpectrum(world.y * ${(57 / NOISE_PERIOD).toFixed(10)}
|
||||
+ abs(position.x) * 0.012 + uSpectrumPhase);
|
||||
vGridColor = mix(cruiseColor, speedSpectrum, uOverdrive * 0.88);
|
||||
vec4 viewPosition = modelViewMatrix * vec4(displaced, 1.0);
|
||||
float viewDistance = -viewPosition.z;
|
||||
vDepthFade = smoothstep(4.0, 18.0, viewDistance)
|
||||
@@ -163,19 +181,18 @@ export function createTerrain(
|
||||
uniform vec3 uHazeColor;
|
||||
uniform float uRouteProgress;
|
||||
uniform float uOverdrive;
|
||||
uniform float uSurge;
|
||||
varying float vHeight;
|
||||
varying float vRoadMask;
|
||||
varying float vDepthFade;
|
||||
varying float vFlow;
|
||||
varying vec3 vTerrainPosition;
|
||||
varying vec3 vGridColor;
|
||||
varying float vCrest;
|
||||
|
||||
void main() {
|
||||
float ridgeMix = smoothstep(0.025, 0.29, vHeight);
|
||||
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.20, 0.25), 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);
|
||||
@@ -185,6 +202,7 @@ export function createTerrain(
|
||||
float surfaceStrength = mix(0.72, 0.12 + uOverdrive * 0.3, road);
|
||||
float alpha = vDepthFade * pulse * routeCalm * mix(surfaceStrength, 0.91, ridgeMix);
|
||||
float charge = uOverdrive * (0.35 + vFlow * 0.8) * (0.5 + apron * 0.5);
|
||||
charge += uSurge * (0.28 + vCrest * 0.5) * (1.0 - road);
|
||||
gl_FragColor = vec4(color * (1.46 + ridgeMix * 0.54 + charge), alpha);
|
||||
#include <tonemapping_fragment>
|
||||
#include <colorspace_fragment>
|
||||
@@ -221,6 +239,7 @@ export function createTerrain(
|
||||
uniform vec3 uLowColor;
|
||||
uniform vec3 uHighColor;
|
||||
uniform vec3 uFogColor;
|
||||
uniform float uSurge;
|
||||
varying float vHeight;
|
||||
varying float vDepthFade;
|
||||
varying vec3 vTerrainPosition;
|
||||
@@ -228,7 +247,7 @@ export function createTerrain(
|
||||
void main() {
|
||||
vec3 normal = normalize(cross(dFdx(vTerrainPosition), dFdy(vTerrainPosition)));
|
||||
float light = abs(dot(normal, normalize(vec3(-0.5, 0.8, -0.3))));
|
||||
vec3 color = mix(vec3(0.012, 0.003, 0.024), vGridColor * 0.065, light);
|
||||
vec3 color = mix(vec3(0.012, 0.003, 0.024), vGridColor * (0.065 + uSurge * 0.016), light);
|
||||
color += uHighColor * pow(vHeight, 2.0) * light * 0.06;
|
||||
color = mix(uFogColor * 0.55, color, vDepthFade);
|
||||
gl_FragColor = vec4(color, 1.0);
|
||||
@@ -254,13 +273,25 @@ export function createTerrain(
|
||||
|
||||
return {
|
||||
group,
|
||||
update(distance, speed, chapter, routeProgress, palette, overdrive = 0) {
|
||||
update(
|
||||
distance,
|
||||
speed,
|
||||
chapter,
|
||||
routeProgress,
|
||||
palette,
|
||||
overdrive = 0,
|
||||
surge = 0,
|
||||
spectrumPhase = 0,
|
||||
) {
|
||||
const chapterPalette = CHAPTER_PALETTES[chapter];
|
||||
uniforms.uDistance.value =
|
||||
((finiteOrZero(distance) % NOISE_PERIOD) + NOISE_PERIOD) % NOISE_PERIOD;
|
||||
uniforms.uFlowDistance.value = uniforms.uDistance.value;
|
||||
uniforms.uSpeed.value = clamp01(speed);
|
||||
uniforms.uOverdrive.value = clamp01(overdrive);
|
||||
uniforms.uSurge.value = clamp01(surge);
|
||||
uniforms.uSpectrumPhase.value =
|
||||
((finiteOrZero(spectrumPhase) % 1) + 1) % 1;
|
||||
uniforms.uRouteProgress.value = clamp01(routeProgress);
|
||||
uniforms.uTerrainEnergy.value =
|
||||
palette?.terrainEnergy ?? chapterPalette.terrainEnergy;
|
||||
|
||||
Reference in New Issue
Block a user