diff --git a/client/shaders/fog.gdshader b/client/shaders/fog.gdshader index 6287eb0ae..99dcb17a4 100644 --- a/client/shaders/fog.gdshader +++ b/client/shaders/fog.gdshader @@ -1,10 +1,9 @@ shader_type canvas_item; -// D-059: 3-state fog shader (simplified from 5-layer by #569). +// D-059/D-015: 3-state fog shader (simplified from 5-layer by #569). // State 1: Clear (forward cone) — transparent, soft Gaussian gradient edge (3-4 tile radius) -// State 2: Explored (out of cone, EXP_EXPLORED) — two sub-zones by vis proximity: -// a) Light fog (near cone gradient): alpha 0.25-0.35, neutral dark, 8-10s breathe -// b) Deep fog (far from cone, vis≈0): alpha 0.55-0.70, zone temperature tint, 15-20s breathe +// State 2: Explored (out of cone) — light fog overlay, alpha 0.25-0.35, zone temperature tint, +// 8-10s Perlin breathe. Art and information preserved, just "not fresh" (D-015). // State 3: Unexplored — solid near-black #12141a // D-033: Entity colors are NOT affected — they render above the fog overlay (z-layer 5). // D-046: Zone temperature tint from zone_tint_tex — warm=bar, cool=hub, neutral=corridor. @@ -23,7 +22,6 @@ uniform float time; // Seconds since start uniform bool debug_exploration = false; // When true, render raw exploration texture const vec3 UNEXPLORED_COLOR = vec3(0.071, 0.078, 0.102); // #12141a -const vec3 DARK_OVERLAY = vec3(0.02, 0.02, 0.05); // neutral dark (light fog zone) // Soft gradient via 7x7 Gaussian blur on visibility (sigma 2.0). // Spreads the cone boundary into a 3-4 tile radius gradient — no hard tile-stepped edges. @@ -42,6 +40,23 @@ float sample_visibility(vec2 uv) { return sum / weight; } +// Soft gradient on exploration boundary (5x5, sigma 1.5). +// Prevents hard tile-stepped staircase at explored/unexplored edge. +float sample_exploration(vec2 uv) { + vec2 t = 1.0 / map_size; + float sum = 0.0; + float weight = 0.0; + for (float dy = -2.0; dy <= 2.0; dy += 1.0) { + for (float dx = -2.0; dx <= 2.0; dx += 1.0) { + float w = exp(-(dx * dx + dy * dy) / 4.5); + vec2 sample_uv = clamp(uv + vec2(dx, dy) * t, vec2(0.0), vec2(1.0)); + sum += texture(exploration_tex, sample_uv).r * w; + weight += w; + } + } + return sum / weight; +} + void fragment() { vec2 world_px = rect_pos + UV * rect_sz; vec2 tile = world_px / tile_size; @@ -69,10 +84,11 @@ void fragment() { float vis_raw = texture(visibility_tex, tex_uv).r; float vis = sample_visibility(tex_uv); - float explored = texture(exploration_tex, tex_uv).r; + float explored_raw = texture(exploration_tex, tex_uv).r; + float explored = sample_exploration(tex_uv); - // Prevent gradient bleed into never-explored tiles - if (explored < 0.01 && vis_raw < 0.01) { + // Prevent gradient bleed into never-explored tiles (use raw, unblurred value) + if (explored_raw < 0.01 && vis_raw < 0.01) { vis = 0.0; } @@ -80,39 +96,19 @@ void fragment() { // Unexplored: solid near-black — information zero COLOR = vec4(UNEXPLORED_COLOR, 1.0); } else { - // Light fog noise — fast cycle (~9s), ±0.05 breathing - float noise_fast = texture(noise_tex, tile * 0.03 + vec2(time * 0.11, time * 0.07)).r; - // Deep fog noise — slow cycle (~20s), ±0.075 breathing (more pronounced) - float noise_slow = texture(noise_tex, tile * 0.02 + vec2(time * 0.05, time * 0.035)).r; + // Fog noise — 8-10s breathe cycle, ±0.05 symmetric around baseline + float noise_val = texture(noise_tex, tile * 0.03 + vec2(time * 0.11, time * 0.07)).r; + float fog_alpha = 0.30 + (noise_val * 2.0 - 1.0) * 0.05; // 0.25-0.35 - // Light fog: alpha 0.25-0.35 (centered at 0.30, ±0.05 breathe) - // Noise remapped to [-1,+1] for symmetric breathing around baseline. - float light_fog_alpha = 0.30 + (noise_fast * 2.0 - 1.0) * 0.05; - - // Deep fog: alpha 0.55-0.70 (centered at 0.625, ±0.075 breathe) - float deep_fog_alpha = 0.625 + (noise_slow * 2.0 - 1.0) * 0.075; - - // Blend deep <-> light fog by proximity to cone: - // vis=0 (far from cone) → deep_factor=1 → deep fog - // vis=0.3 (cone gradient) → deep_factor=0 → light fog - // vis=0.85+ (inside cone) → clarity=1 → transparent (clear) - float deep_factor = 1.0 - smoothstep(0.0, 0.30, vis); - float fog_alpha = mix(light_fog_alpha, deep_fog_alpha, deep_factor); - - // Zone temperature tint (D-059/D-046/D-077): - // Deep fog color uses zone_tint_tex; light fog uses neutral DARK_OVERLAY. - // zone_tint_tex is populated per-tile from server zone_id via fog_state.gd. + // Zone temperature tint (D-046/D-077): subtle warm/cool/neutral per zone vec3 zone_tint = texture(zone_tint_tex, tex_uv).rgb; - // Clarity ramp: transparent inside cone, fogged at edges and beyond + // Clarity ramp: transparent inside cone, light fog at edges and beyond float clarity = smoothstep(0.0, 0.85, vis); float alpha = mix(fog_alpha, 0.0, clarity); + vec3 color = mix(zone_tint, vec3(0.0), clarity); - // Color: deep fog → zone temperature tint; light fog → neutral dark overlay - vec3 fog_color = mix(DARK_OVERLAY, zone_tint, deep_factor); - vec3 color = mix(fog_color, vec3(0.0), clarity); - - // Soft edge between explored and unexplored + // Soft edge between explored and unexplored (blurred to avoid staircase) float exp_fade = smoothstep(0.0, 0.3, explored); alpha = mix(1.0, alpha, exp_fade); color = mix(UNEXPLORED_COLOR, color, exp_fade);