extends Node @export var cycle_duration_seconds := 240.0 @export_range(0.0, 1.0, 0.01) var initial_cycle := 0.35 @export var directional_light: DirectionalLight3D @export var world_environment: WorldEnvironment const TO_RAD := PI / 180.0 const DAY_SKY_TOP := Color(0.23, 0.43, 0.62, 1) const DAY_SKY_HORIZON := Color(0.82, 0.68, 0.5, 1) const DAY_GROUND_BOTTOM := Color(0.12, 0.17, 0.12, 1) const DAY_GROUND_HORIZON := Color(0.62, 0.55, 0.42, 1) const DAY_AMBIENT := Color(0.91, 0.85, 0.72, 1) const DAY_AMBIENT_ENERGY := 0.7 const DAY_FOG_LIGHT := Color(0.82, 0.78, 0.66, 1) const DAY_FOG_LIGHT_ENERGY := 0.72 const DAY_FOG_DENSITY := 0.002 const DAY_LIGHT_COLOR := Color(1, 0.87, 0.72, 1) const DAY_LIGHT_ENERGY := 1.45 const NIGHT_SKY_TOP := Color(0.04, 0.04, 0.12, 1) const NIGHT_SKY_HORIZON := Color(0.08, 0.06, 0.14, 1) const NIGHT_GROUND_BOTTOM := Color(0.02, 0.02, 0.04, 1) const NIGHT_GROUND_HORIZON := Color(0.04, 0.03, 0.06, 1) const NIGHT_AMBIENT := Color(0.12, 0.14, 0.28, 1) const NIGHT_AMBIENT_ENERGY := 0.25 const NIGHT_FOG_LIGHT := Color(0.1, 0.12, 0.24, 1) const NIGHT_FOG_LIGHT_ENERGY := 0.3 const NIGHT_FOG_DENSITY := 0.005 const NIGHT_LIGHT_COLOR := Color(0.22, 0.28, 0.5, 1) const NIGHT_LIGHT_ENERGY := 0.3 const SUNSET_LIGHT_COLOR := Color(1, 0.55, 0.3, 1) const SUNRISE_LIGHT_COLOR := Color(1, 0.6, 0.45, 1) const SUNRISE_SUNSET_ENERGY := 0.8 var elapsed := 0.0 func _ready() -> void: elapsed = cycle_duration_seconds * initial_cycle _apply_light_rotation(initial_cycle) _apply_environment(initial_cycle) func _process(delta: float) -> void: elapsed += delta if elapsed >= cycle_duration_seconds: elapsed = fmod(elapsed, cycle_duration_seconds) var cycle := elapsed / cycle_duration_seconds _apply_light_rotation(cycle) _apply_environment(cycle) func _apply_light_rotation(cycle: float) -> void: if directional_light == null: return var angle_rad: float = cycle * 2.0 * PI directional_light.rotation = Vector3(-PI / 4.0 + sin(angle_rad) * PI / 4.0, angle_rad, 0) func _apply_environment(cycle: float) -> void: if directional_light == null: return var day_factor := _day_factor(cycle) var night_factor := 1.0 - day_factor directional_light.light_color = _lerp_color(NIGHT_LIGHT_COLOR, DAY_LIGHT_COLOR, day_factor) directional_light.light_energy = lerpf(NIGHT_LIGHT_ENERGY, DAY_LIGHT_ENERGY, day_factor) var sunset_peak := _sunrise_sunset_weight(cycle) if sunset_peak > 0.0: var sunset_color: Color if cycle < 0.5: sunset_color = SUNSET_LIGHT_COLOR else: sunset_color = SUNRISE_LIGHT_COLOR directional_light.light_color = directional_light.light_color.lerp( sunset_color, sunset_peak * 0.85 ) directional_light.light_energy = maxf( directional_light.light_energy, SUNRISE_SUNSET_ENERGY * sunset_peak ) if world_environment == null or world_environment.environment == null: return var env: Environment = world_environment.environment env.ambient_light_color = _lerp_color(NIGHT_AMBIENT, DAY_AMBIENT, day_factor) env.ambient_light_energy = lerpf(NIGHT_AMBIENT_ENERGY, DAY_AMBIENT_ENERGY, day_factor) env.fog_light_color = _lerp_color(NIGHT_FOG_LIGHT, DAY_FOG_LIGHT, day_factor) env.fog_light_energy = lerpf(NIGHT_FOG_LIGHT_ENERGY, DAY_FOG_LIGHT_ENERGY, day_factor) env.fog_density = lerpf(NIGHT_FOG_DENSITY, DAY_FOG_DENSITY, day_factor) var sky: Sky = env.sky if sky != null and sky.sky_material is ProceduralSkyMaterial: var mat: ProceduralSkyMaterial = sky.sky_material mat.sky_top_color = _lerp_color(NIGHT_SKY_TOP, DAY_SKY_TOP, day_factor) mat.sky_horizon_color = _lerp_color(NIGHT_SKY_HORIZON, DAY_SKY_HORIZON, day_factor) mat.ground_bottom_color = _lerp_color(NIGHT_GROUND_BOTTOM, DAY_GROUND_BOTTOM, day_factor) mat.ground_horizon_color = _lerp_color(NIGHT_GROUND_HORIZON, DAY_GROUND_HORIZON, day_factor) func _day_factor(cycle: float) -> float: if cycle < 0.15: return 0.0 if cycle < 0.3: return smoothstep(0.15, 0.3, cycle) if cycle < 0.7: return 1.0 if cycle < 0.85: return 1.0 - smoothstep(0.7, 0.85, cycle) return 0.0 func _sunrise_sunset_weight(cycle: float) -> float: if cycle < 0.15: return smoothstep(0.05, 0.15, cycle) * (1.0 - smoothstep(0.1, 0.15, cycle)) if cycle > 0.85: return smoothstep(0.85, 0.95, cycle) * (1.0 - smoothstep(0.9, 0.95, cycle)) return 0.0 func _lerp_color(from: Color, to: Color, weight: float) -> Color: return from.lerp(to, clampf(weight, 0.0, 1.0))