@tool class_name WeatherController extends Node var particles_wind: GPUParticles3D var particles_snow: GPUParticles3D var particles_fireflies: GPUParticles3D var particles_rain: GPUParticles3D var godray: PackedScene var fog_overlay: ColorRect var sun: DirectionalLight3D var environment: WorldEnvironment var environment_config: EnvironmentConfig var day_time: float = 0.0 var lightning_sprite: Sprite3D var lightning_light = DirectionalLight3D.new(); var timer_next_lightning: float = 0.0 var is_raining: bool = false var rain_intensity: float = 0.0 var rain_tween: Tween var snow_tween: Tween var snow_particles_tween: Tween var is_snowing: bool = false var is_snow_accumulated: bool = false var actual_snow_amount: float = 0.0 var cold_tween: Tween var is_windy: bool = false var thereare_fireflies: bool = false func _init(wind: GPUParticles3D, snow: GPUParticles3D, fireflies: GPUParticles3D, rain: GPUParticles3D, ray: PackedScene, thesun: DirectionalLight3D, theenvironment: WorldEnvironment, environmentconfig: EnvironmentConfig) -> void: particles_wind = wind particles_snow = snow particles_fireflies = fireflies particles_rain = rain godray = ray sun = thesun environment = theenvironment environment_config = environmentconfig set_rain() set_fireflies() set_wind() set_snow() set_lightning() func _ready() -> void: #connect events UIEvents.toggle_rain.connect(toggle_rain) UIEvents.toggle_snow.connect(toggle_snow) UIEvents.toggle_wind.connect(toggle_wind) UIEvents.toggle_fireflies.connect(toggle_fireflies) func _process(delta: float) -> void: var base_tint: Color var base_sky_top: Color var base_sky_horizon: Color var base_fog_color: Color var base_fog_density: float var base_bloom: float var base_exposure: float var base_grad_top: Color var base_grad_bot: Color var base_grad_intensity: float var base_rotation_sun: Vector3 var storm_is_active = is_raining and is_snowing if storm_is_active: rain_intensity = move_toward(rain_intensity, 1.0, delta * 0.5) if is_raining: timer_next_lightning -= delta if timer_next_lightning <= 0.0: start_lightning() set_lightning_timer() else: rain_intensity = move_toward(rain_intensity, 0.0, delta * 0.5) if environment_config.material_clouds: var current_density = lerp(0.4, 1.0, rain_intensity) environment_config.material_clouds.set_shader_parameter("cloud_density", current_density) var current_sharpness = lerp(0.14, 0.0, rain_intensity) environment_config.material_clouds.set_shader_parameter("center_sharpness", current_sharpness) if day_time <= 2.0: var t = day_time - 1.0 base_tint = environment_config.morning_color.lerp(environment_config.afternoon_color, t) base_sky_top = environment_config.sky_top_morning.lerp(environment_config.sky_top_afternoon, t) base_sky_horizon = environment_config.sky_horizon_morning.lerp(environment_config.sky_horizon_afternoon, t) base_fog_color = environment_config.fog_color_morning.lerp(environment_config.fog_color_afternoon, t) base_fog_density = lerp(environment_config.fog_density_morning, environment_config.fog_density_afternoon, t) base_bloom = lerp(environment_config.glow_morning, environment_config.glow_afternoon, t) base_exposure = lerp(environment_config.exposure_morning, environment_config.exposure_afternoon, t) base_grad_top = environment_config.grad_top_morning.lerp(environment_config.grad_top_afternoon, t) base_grad_bot = environment_config.grad_top_morning.lerp(environment_config.grad_bot_afternoon, t) base_grad_intensity = lerp(environment_config.grad_intensity_morning, environment_config.grad_intensity_afternoon, t) base_rotation_sun = environment_config.sun_rotation_morning.lerp(environment_config.sun_rotation_afternoon, t) else: var t = day_time - 2.0 base_tint = environment_config.afternoon_color.lerp(environment_config.night_color, t) base_sky_top = environment_config.sky_top_afternoon.lerp(environment_config.sky_top_night, t) base_sky_horizon = environment_config.sky_horizon_afternoon.lerp(environment_config.sky_horizon_night, t) base_fog_color = environment_config.fog_color_afternoon.lerp(environment_config.fog_color_night, t) base_fog_density = lerp(environment_config.fog_density_afternoon, environment_config.fog_density_night, t) base_bloom = lerp(environment_config.glow_afternoon, environment_config.glow_night, t) base_exposure = lerp(environment_config.exposure_afternoon, environment_config.exposure_night, t) base_grad_top = environment_config.grad_top_afternoon.lerp(environment_config.grad_top_night, t) base_grad_bot = environment_config.grad_bot_afternoon.lerp(environment_config.grad_bot_night, t) base_grad_intensity = lerp(environment_config.grad_intensity_afternoon, environment_config.grad_intensity_night, t) base_rotation_sun = environment_config.sun_rotation_afternoon.lerp(environment_config.sun_rotation_night, t) var final_tint = base_tint.lerp(base_tint * environment_config.rain_mode_color, rain_intensity) var final_sky_top = base_sky_top.lerp(base_sky_top * environment_config.rain_mode_color, rain_intensity) var final_sky_horizon = base_sky_horizon.lerp(base_sky_horizon * environment_config.rain_mode_color, rain_intensity) var final_fog_color = base_fog_color.lerp(base_fog_color * environment_config.rain_mode_color, rain_intensity) var final_fog_density = lerp(base_fog_density, base_fog_density * 4.0, rain_intensity) #Shader parameters for global trunk_shader var final_grad_top = base_grad_top.lerp(base_grad_top * environment_config.rain_mode_color, rain_intensity) var final_grad_bot = base_grad_bot.lerp(base_grad_bot * environment_config.rain_mode_color, rain_intensity) RenderingServer.global_shader_parameter_set("global_gradient_color_top", final_grad_top) RenderingServer.global_shader_parameter_set("global_gradient_color_bot", final_grad_bot) RenderingServer.global_shader_parameter_set("global_gradient_intensity", base_grad_intensity) var night_val = clamp(day_time - 2.0, 0.0, 1.0) #Snow exposure compensation var snow_light_attenuation = lerp(1.0, 0.55, actual_snow_amount * (1.0 - night_val)) var snow_glow_attenuation = lerp(1.0, 0.5, actual_snow_amount) var final_bloom = lerp(base_bloom, base_bloom * 0.5, rain_intensity) * snow_glow_attenuation # We calculate the final exposure by applying snow damping directly to the camera exposure var final_esposizione = base_exposure * snow_light_attenuation var reflected_color = Color(0.4, 0.5, 0.6, 1.0) var drops_color = final_sky_horizon.lerp(reflected_color, 0.15) drops_color = drops_color.lerp(drops_color * 0.4, night_val) if environment_config.material_drops: environment_config.material_drops.albedo_color = drops_color if sun: sun.light_color = final_tint sun.rotation_degrees = base_rotation_sun #var target_energy = lerp(1.0, night_light_energy, night_val) # Sunlight scales normally based on weather/night (global exposure does the rest of the work) #sun.light_energy = lerp(target_energy, target_energy * 0.4, rain_intensity) if environment and environment.environment: environment.environment.ambient_light_color = final_tint # Apply fog environment.environment.fog_enabled = true environment.environment.fog_light_color = final_fog_color environment.environment.fog_density = final_fog_density # Apply glow environment.environment.glow_enabled = true environment.environment.glow_intensity = final_bloom # Make sure the Tonemap Mode in the Environment is set to ACES or Filmic for best results! environment.environment.tonemap_exposure = final_esposizione var sky_mat = environment.environment.sky.sky_material as ShaderMaterial if sky_mat: sky_mat.set_shader_parameter("sky_top_color", final_sky_top) sky_mat.set_shader_parameter("sky_horizon_color", final_sky_horizon) sky_mat.set_shader_parameter("sun_color", final_tint) sky_mat.set_shader_parameter("night_intensity", night_val) if environment_config.material_fog: environment_config.material_fog.set_shader_parameter("night_intensity", night_val) environment_config.material_fog.set_shader_parameter("sun_color", final_tint) var e_night = day_time >= 2.5 #if nodo_polvere: #nodo_polvere.visible = (not storm_is_active and not e_night) if particles_fireflies: particles_fireflies.emitting = (not storm_is_active and e_night and thereare_fireflies) if particles_wind: particles_wind.emitting = (not storm_is_active and not e_night and is_windy) #region fireflies func toggle_fireflies(value: bool): thereare_fireflies = value #disable fireflies and set default values and materials func set_fireflies(): if particles_fireflies: particles_fireflies.visible = true particles_fireflies.emitting = false particles_fireflies.amount = environment_config.fireflies_amount var proc_mat = particles_fireflies.process_material as ParticleProcessMaterial if proc_mat: proc_mat.emission_box_extents = Vector3(environment_config.fireflies_spawn_ray, environment_config.fireflies_spawn_height, environment_config.fireflies_spawn_ray) #endregion #region Wind func toggle_wind(value: bool): is_windy = value #disable wind and set default values and materials func set_wind(): if particles_wind: particles_wind.visible = true particles_wind.emitting = false particles_wind.amount = environment_config.wind_amount var proc_mat_wind = particles_wind.process_material as ParticleProcessMaterial if proc_mat_wind: proc_mat_wind.emission_box_extents = Vector3(environment_config.wind_spawn_ray, environment_config.wind_spawn_height, environment_config.wind_spawn_ray) #endregion #region Lightning #set lightning func set_lightning(): lightning_light.name = "Lightning Light" lightning_light.transform = Transform3D( Vector3(-0.6238797, -0.342596, 0.7024259), # asse X Vector3(0.0, 0.89879405, 0.43837115), # asse Y Vector3(-0.7815204, 0.27349085, -0.56073934), # asse Z Vector3(0.0, 0.0, 30.411049) # origine ) lightning_light.light_color = Color(0.8, 1.0, 1.0, 1.0) lightning_light.light_energy = 0.0 lightning_light.shadow_enabled = true add_child(lightning_light) create_lightning_sprite() set_lightning_timer() func create_lightning_sprite(): lightning_sprite = Sprite3D.new() lightning_sprite.name = "Lightning Sprite" lightning_sprite.transform = Transform3D( Basis( Vector3(4, 0, 0), Vector3(0, 7.32, 0), Vector3(0, 0, 7.3) ), Vector3(0, 17.324, 30.411049) ) lightning_sprite.modulate = Color(1, 1, 1, 0) lightning_sprite.billboard = BaseMaterial3D.BILLBOARD_ENABLED lightning_sprite.alpha_cut = SpriteBase3D.ALPHA_CUT_DISCARD #Add Texture lightning_sprite.texture = load(environment_config.lightning_texture) add_child(lightning_sprite) #set next lightning timer func set_lightning_timer(): timer_next_lightning = randf_range(environment_config.lightning_min_time, environment_config.lightning_max_time) func start_lightning(): if lightning_light: var tween_luce = create_tween() lightning_light.light_energy = 5.0 tween_luce.tween_interval(0.05) tween_luce.tween_callback(func(): lightning_light.light_energy = 0.0) tween_luce.tween_interval(0.05) tween_luce.tween_callback(func(): lightning_light.light_energy = 2.0) tween_luce.tween_method(func(val): lightning_light.light_energy = val, 2.0, 0.0, 0.2) var lightning_number = randi_range(environment_config.lightning_min, environment_config.lightning_max) for i in lightning_number: if lightning_sprite: var angolo_casuale = randf() * TAU var distanza = randf_range(10.0, 40.0) lightning_sprite.position = Vector3(cos(angolo_casuale) * distanza, 10.0, sin(angolo_casuale) * distanza) lightning_sprite.modulate = environment_config.lightning_color lightning_sprite.modulate.a = 1.0 var s = randf_range(environment_config.lightning_scale_min, environment_config.lightning_scale_max) lightning_sprite.scale = Vector3(s, s, s) var tween_sprite = create_tween() tween_sprite.tween_interval(0.2) tween_sprite.tween_property(lightning_sprite, "modulate:a", 0.0, 0.4) if lightning_number > 1: await get_tree().create_timer(randf_range(0.05, 0.15)).timeout #endregion #region Rain #disable rain func set_rain(): if particles_rain: particles_rain.visible = true particles_rain.emitting = false func toggle_rain(value: bool): is_raining = value if not particles_rain: return if is_raining and is_snowing: toggle_snow(false) if rain_tween and rain_tween.is_valid(): rain_tween.kill() if is_raining: particles_rain.amount_ratio = 0.0 particles_rain.emitting = true rain_tween = create_tween() rain_tween.tween_property(particles_rain, "amount_ratio", 1.0, environment_config.rain_fade_time) else: rain_tween = create_tween() rain_tween.tween_property(particles_rain, "amount_ratio", 0.0, environment_config.rain_fade_time) rain_tween.tween_callback(func(): particles_rain.emitting = false trigger_after_rain()) func trigger_morning() -> void: spawn_single_godray() func trigger_after_rain() -> void: if day_time < 2.5: var count: int = randi_range(1, environment_config.godray_max_rain) for i in count: spawn_single_godray() func spawn_single_godray() -> void: var ray: Node3D = godray.instantiate() get_tree().current_scene.add_child(ray) var random_x: float = randf_range(-environment_config.godray_spawn_radius, environment_config.godray_spawn_radius) var random_z: float = randf_range(-environment_config.godray_spawn_radius, environment_config.godray_spawn_radius) #TODO: FLAVIO: fix global position using the camera position if needed ray.global_position = Vector3(random_x, environment_config.godray_spawn_height, random_z) ray.rotation_degrees = environment_config.godray_rotation_degrees ray.scale = environment_config.godray_scale var godray_tween: Tween = create_tween() godray_tween.tween_interval(2.0) godray_tween.tween_property(ray, "scale", Vector3.ZERO, 2.0).set_ease(Tween.EASE_IN).set_trans(Tween.TRANS_SINE) godray_tween.tween_callback(ray.queue_free) #endregion #region Snow func toggle_snow(value: bool): is_snowing = value if is_snowing and is_raining: toggle_rain(false) # Fade particelle neve if particles_snow: if snow_particles_tween and snow_particles_tween.is_valid(): snow_particles_tween.kill() if is_snowing: particles_snow.amount_ratio = 0.0 particles_snow.visible = true particles_snow.emitting = true snow_particles_tween = create_tween() snow_particles_tween.tween_property(particles_snow, "amount_ratio", 1.0, environment_config.snow_fade_time) else: snow_particles_tween = create_tween() snow_particles_tween.tween_property(particles_snow, "amount_ratio", 0.0, environment_config.snow_fade_time) snow_particles_tween.tween_callback(func(): particles_snow.emitting = false) # Accumulo neve sulle superfici var target_snow: float = 1.0 if is_snowing else 0.0 if snow_tween and snow_tween.is_valid(): snow_tween.kill() snow_tween = create_tween() snow_tween.tween_method(set_snow_amount, actual_snow_amount, target_snow, environment_config.snow_transaction_time) if fog_overlay and fog_overlay.material: var target_opacity: float = 0.5 if is_snowing else 0.1 var target_radius: float = 0.350 if is_snowing else 0.465 if cold_tween and cold_tween.is_valid(): cold_tween.kill() cold_tween = create_tween() cold_tween.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT) cold_tween.set_parallel(true) cold_tween.tween_property(fog_overlay.material, "shader_parameter/max_opacity", target_opacity, 4.0) cold_tween.tween_property(fog_overlay.material, "shader_parameter/clear_center_radius", target_radius, 4.0) #disable snow and set default values and shader func set_snow(value: float = 0.0): actual_snow_amount = value RenderingServer.global_shader_parameter_set("global_snow_amount", value) if particles_snow: particles_snow.emitting = false particles_snow.amount = environment_config.snow_amount func set_snow_amount(value: float): actual_snow_amount = value RenderingServer.global_shader_parameter_set("global_snow_amount", value) #endregion #func _genera_evento_meteo_casuale() -> void: #sto_cambiando_in_cinematic = true # #var scelta = randi() % 3 # #if scelta == 0: #var nuovo_orario = randi() % 3 #if menu_giornata: #menu_giornata.selected = nuovo_orario #_on_giornata_selezionata(nuovo_orario) # #elif scelta == 1: #if not is_snowing: #var piove = randf() > 0.5 #if bottone_pioggia: #bottone_pioggia.set_pressed_no_signal(piove) #_on_pioggia_toggled(piove) # #elif scelta == 2: #if not is_snowing: #if not is_raining: #if bottone_pioggia: #bottone_pioggia.set_pressed_no_signal(true) #_on_pioggia_toggled(true) #_scatena_fulmine()