Files
tgcc/core/daynight/weather_controller.gd
2026-03-31 23:59:04 +02:00

546 lines
21 KiB
GDScript

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 environment_dust: ColorRect
var blur: ColorRect
var environment_shadows: MeshInstance3D
var sun: DirectionalLight3D
var environment: WorldEnvironment
var environment_config: EnvironmentConfig
var camera: Camera3D
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 puddle_tween: Tween
var puddle_amount: float = 0.0
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 is_storm: bool = false
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,
fogov: ColorRect, dust: ColorRect, blurr: ColorRect, envshadows: MeshInstance3D,
thesun: DirectionalLight3D, theenvironment: WorldEnvironment, environmentconfig: EnvironmentConfig,
thecamera: Camera3D = null) -> void:
particles_wind = wind
particles_snow = snow
particles_fireflies = fireflies
particles_rain = rain
godray = ray
sun = thesun
fog_overlay = fogov
environment_dust = dust
blur = blurr
environment_shadows = envshadows
environment = theenvironment
environment_config = environmentconfig
camera = thecamera
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)
UIEvents.toggle_storm.connect(toggle_storm)
#UIEvents.toggle_fog_overlay.connect(toggle_fog_overlay)
UIEvents.toggle_dust.connect(toggle_dust)
UIEvents.toggle_blur.connect(toggle_blur)
UIEvents.toggle_shadows.connect(toggle_shadows)
func _process(delta: float) -> void:
_follow_camera()
var is_night = day_time >= 2.5
if particles_fireflies:
particles_fireflies.emitting = thereare_fireflies and is_night
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
if is_raining:
rain_intensity = move_toward(rain_intensity, 1.0, delta * 0.5)
if is_storm:
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)
RenderingServer.global_shader_parameter_set("global_rain_intensity", rain_intensity)
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)
final_tint = final_tint.lerp(final_tint * environment_config.snow_mode_color, actual_snow_amount)
final_sky_top = final_sky_top.lerp(final_sky_top * environment_config.snow_mode_color, actual_snow_amount)
final_sky_horizon = final_sky_horizon.lerp(final_sky_horizon * environment_config.snow_mode_color, actual_snow_amount)
final_fog_color = final_fog_color.lerp(final_fog_color * environment_config.snow_mode_color, actual_snow_amount)
#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, environment_config.night_light_energy, night_val)
# Sunlight scales based on weather/night
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_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 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)
func _follow_camera() -> void:
if not camera or not is_instance_valid(camera):
return
var cam_pos: Vector3 = camera.global_position
if particles_rain:
particles_rain.global_position = Vector3(cam_pos.x, particles_rain.position.y, cam_pos.z)
if particles_snow:
particles_snow.global_position = Vector3(cam_pos.x, particles_snow.position.y, cam_pos.z)
if particles_wind:
particles_wind.global_position = Vector3(cam_pos.x, particles_wind.position.y, cam_pos.z)
if particles_fireflies:
particles_fireflies.global_position = Vector3(cam_pos.x, particles_fireflies.position.y, cam_pos.z)
#region Fireflies
func toggle_fireflies(value: bool):
thereare_fireflies = value
var is_night = day_time >= 2.5
if particles_fireflies:
particles_fireflies.emitting = thereare_fireflies and is_night
#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
var is_night = day_time >= 2.5
if particles_wind:
particles_wind.emitting = (not is_storm and not is_night and is_windy)
#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)
if environment_config:
_apply_cloud_config()
_apply_wind_config()
func _apply_wind_config() -> void:
RenderingServer.global_shader_parameter_set("global_wind_speed", environment_config.wind_speed)
RenderingServer.global_shader_parameter_set("global_wind_direction", environment_config.wind_direction)
RenderingServer.global_shader_parameter_set("global_wind_scale", environment_config.wind_scale)
RenderingServer.global_shader_parameter_set("global_wind_strength", environment_config.wind_strength)
func _apply_cloud_config() -> void:
var dir = environment_config.wind_direction
var cloud_scale = environment_config.cloud_scale
var cloud_speed = environment_config.cloud_speed
var envshadows_scale_rate = environment_config.cloud_scale_envshadows_rate
var envshadows_speed_rate = environment_config.cloud_speed_envshadows_rate
if environment and environment.environment and environment.environment.sky:
var sky_mat = environment.environment.sky.sky_material as ShaderMaterial
if sky_mat:
sky_mat.set_shader_parameter("cloud_direction", dir)
sky_mat.set_shader_parameter("cloud_scale", cloud_scale)
sky_mat.set_shader_parameter("cloud_speed", cloud_speed)
var env_shadow_mat = environment_shadows.get_surface_override_material(0) if environment_shadows else null
if env_shadow_mat:
env_shadow_mat.set_shader_parameter("direction", dir)
env_shadow_mat.set_shader_parameter("cloud_scale", cloud_scale * envshadows_scale_rate)
env_shadow_mat.set_shader_parameter("cloud_speed", cloud_speed * envshadows_speed_rate)
if environment_config.material_clouds:
environment_config.material_clouds.set_shader_parameter("direction", dir)
environment_config.material_clouds.set_shader_parameter("cloud_scale", cloud_scale * envshadows_scale_rate)
environment_config.material_clouds.set_shader_parameter("cloud_speed", cloud_speed * envshadows_speed_rate)
#endregion
#region Lightning
func toggle_storm(value: bool):
is_storm = value
#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_lighting = create_tween()
lightning_light.light_energy = 5.0
tween_lighting.tween_interval(0.05)
tween_lighting.tween_callback(func(): lightning_light.light_energy = 0.0)
tween_lighting.tween_interval(0.05)
tween_lighting.tween_callback(func(): lightning_light.light_energy = 2.0)
tween_lighting.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 random_angle = randf() * TAU
var distance = randf_range(10.0, 40.0)
lightning_sprite.position = Vector3(cos(random_angle) * distance, 10.0, sin(random_angle) * distance)
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
RenderingServer.global_shader_parameter_set("global_rain_puddle_amount", 0.0)
func set_puddle_amount(value: float):
puddle_amount = value
RenderingServer.global_shader_parameter_set("global_rain_puddle_amount", value)
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 puddle_tween and puddle_tween.is_valid():
puddle_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)
puddle_tween = create_tween()
puddle_tween.tween_method(set_puddle_amount, puddle_amount, 1.0, environment_config.puddle_form_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())
puddle_tween = create_tween()
puddle_tween.tween_method(set_puddle_amount, puddle_amount, 0.0, environment_config.puddle_dry_time)
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)
var center := Vector3.ZERO
if camera and is_instance_valid(camera):
center = camera.global_position
ray.global_position = Vector3(center.x + random_x, environment_config.godray_spawn_height, center.z + 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)
start_snow_accumulation()
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)
start_snow_melt()
var target_snow_amount: 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_amount, environment_config.snow_transaction_time)
#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
if environment_config:
RenderingServer.global_shader_parameter_set("global_snow_threshold", environment_config.snow_threshold)
RenderingServer.global_shader_parameter_set("global_snow_color", environment_config.snow_color)
RenderingServer.global_shader_parameter_set("global_snow_accumulation_speed", environment_config.snow_accumulation_speed)
RenderingServer.global_shader_parameter_set("global_snow_melt_speed", environment_config.snow_melt_speed)
RenderingServer.global_shader_parameter_set("global_snow_start_time", -1.0)
RenderingServer.global_shader_parameter_set("global_snow_melt_time", -1.0)
func set_snow_amount(value: float):
actual_snow_amount = value
RenderingServer.global_shader_parameter_set("global_snow_amount", value)
func start_snow_accumulation() -> void:
RenderingServer.global_shader_parameter_set("global_snow_melt_time", -1.0)
RenderingServer.global_shader_parameter_set("global_snow_start_time", Time.get_ticks_msec() / 1000.0)
func start_snow_melt() -> void:
RenderingServer.global_shader_parameter_set("global_snow_melt_time", Time.get_ticks_msec() / 1000.0)
RenderingServer.global_shader_parameter_set("global_snow_melt_speed", environment_config.snow_melt_speed)
#endregion
#region Post-Process
func toggle_dust(value: bool) -> void:
if environment_dust:
environment_dust.visible = value
func toggle_blur(value: bool) -> void:
if blur:
blur.visible = value
func toggle_shadows(value: bool) -> void:
if environment_shadows:
environment_shadows.visible = value
#endregion