This commit is contained in:
Overside srl
2026-02-17 08:37:55 +01:00
parent 65bb24ff6a
commit b158a646c3
17 changed files with 889 additions and 85 deletions

View File

@@ -61,6 +61,11 @@ const NOON := 0.5
@export var fog_color_curve: Gradient
@export var fog_density_curve: Curve
@export_group("Sky Gradient Curves")
@export var sky_top_color_curve: Gradient
@export var sky_horizon_color_curve: Gradient
@export var sky_bottom_color_curve: Gradient
@export_group("Stars")
@export var stars_visibility_curve: Curve
@@ -117,10 +122,10 @@ func _initialize_default_curves() -> void:
if moon_intensity_curve == null:
moon_intensity_curve = Curve.new()
moon_intensity_curve.add_point(Vector2(0.0, 0.4))
moon_intensity_curve.add_point(Vector2(0.2, 0.3))
moon_intensity_curve.add_point(Vector2(0.25, 0.0))
moon_intensity_curve.add_point(Vector2(0.75, 0.0))
moon_intensity_curve.add_point(Vector2(0.85, 0.3))
moon_intensity_curve.add_point(Vector2(0.15, 0.3))
moon_intensity_curve.add_point(Vector2(0.22, 0.0))
moon_intensity_curve.add_point(Vector2(0.85, 0.0))
moon_intensity_curve.add_point(Vector2(0.92, 0.3))
moon_intensity_curve.add_point(Vector2(1.0, 0.4))
if ambient_color_curve == null:
@@ -133,11 +138,13 @@ func _initialize_default_curves() -> void:
if ambient_intensity_curve == null:
ambient_intensity_curve = Curve.new()
ambient_intensity_curve.add_point(Vector2(0.0, 0.2))
ambient_intensity_curve.add_point(Vector2(0.25, 0.5))
ambient_intensity_curve.add_point(Vector2(0.5, 0.7))
ambient_intensity_curve.add_point(Vector2(0.75, 0.5))
ambient_intensity_curve.add_point(Vector2(1.0, 0.2))
ambient_intensity_curve.add_point(Vector2(0.0, 0.05))
ambient_intensity_curve.add_point(Vector2(0.2, 0.1))
ambient_intensity_curve.add_point(Vector2(0.3, 0.5))
ambient_intensity_curve.add_point(Vector2(0.5, 0.6))
ambient_intensity_curve.add_point(Vector2(0.7, 0.5))
ambient_intensity_curve.add_point(Vector2(0.85, 0.1))
ambient_intensity_curve.add_point(Vector2(1.0, 0.05))
if fog_color_curve == null:
fog_color_curve = Gradient.new()
@@ -155,6 +162,37 @@ func _initialize_default_curves() -> void:
fog_density_curve.add_point(Vector2(0.75, 0.015))
fog_density_curve.add_point(Vector2(1.0, 0.02))
if sky_top_color_curve == null:
sky_top_color_curve = Gradient.new()
sky_top_color_curve.set_color(0, Color(0.01, 0.01, 0.04)) # Midnight
sky_top_color_curve.add_point(0.2, Color(0.03, 0.05, 0.1)) # Pre-dawn
sky_top_color_curve.add_point(0.3, Color(0.18, 0.35, 0.8)) # Morning
sky_top_color_curve.add_point(0.5, Color(0.15, 0.35, 0.82)) # Noon
sky_top_color_curve.add_point(0.75, Color(0.12, 0.15, 0.4)) # Sunset
sky_top_color_curve.add_point(0.85, Color(0.02, 0.02, 0.06)) # Dusk end
sky_top_color_curve.set_color(1, Color(0.01, 0.01, 0.04)) # Midnight
if sky_horizon_color_curve == null:
sky_horizon_color_curve = Gradient.new()
sky_horizon_color_curve.set_color(0, Color(0.03, 0.04, 0.08)) # Midnight
sky_horizon_color_curve.add_point(0.2, Color(0.3, 0.22, 0.28)) # Pre-dawn
sky_horizon_color_curve.add_point(0.25, Color(0.85, 0.55, 0.45))# Dawn
sky_horizon_color_curve.add_point(0.35, Color(0.45, 0.6, 0.85))# Morning
sky_horizon_color_curve.add_point(0.5, Color(0.5, 0.65, 0.88)) # Noon
sky_horizon_color_curve.add_point(0.75, Color(0.95, 0.45, 0.25))# Sunset
sky_horizon_color_curve.add_point(0.85, Color(0.06, 0.06, 0.1))# Dusk end
sky_horizon_color_curve.set_color(1, Color(0.03, 0.04, 0.08)) # Midnight
if sky_bottom_color_curve == null:
sky_bottom_color_curve = Gradient.new()
sky_bottom_color_curve.set_color(0, Color(0.02, 0.02, 0.05)) # Midnight
sky_bottom_color_curve.add_point(0.2, Color(0.12, 0.1, 0.15)) # Pre-dawn
sky_bottom_color_curve.add_point(0.3, Color(0.35, 0.45, 0.55)) # Morning
sky_bottom_color_curve.add_point(0.5, Color(0.35, 0.45, 0.55)) # Noon
sky_bottom_color_curve.add_point(0.75, Color(0.3, 0.2, 0.2)) # Sunset
sky_bottom_color_curve.add_point(0.85, Color(0.03, 0.03, 0.06))# Dusk end
sky_bottom_color_curve.set_color(1, Color(0.02, 0.02, 0.05)) # Midnight
if stars_visibility_curve == null:
stars_visibility_curve = Curve.new()
stars_visibility_curve.add_point(Vector2(0.0, 1.0))
@@ -286,6 +324,24 @@ func get_stars_visibility() -> float:
return 0.0
func get_sky_top_color() -> Color:
if sky_top_color_curve:
return sky_top_color_curve.sample(time_of_day)
return Color(0.2, 0.4, 0.8)
func get_sky_horizon_color() -> Color:
if sky_horizon_color_curve:
return sky_horizon_color_curve.sample(time_of_day)
return Color(0.6, 0.7, 0.9)
func get_sky_bottom_color() -> Color:
if sky_bottom_color_curve:
return sky_bottom_color_curve.sample(time_of_day)
return Color(0.4, 0.5, 0.6)
func is_daytime() -> bool:
return time_of_day >= SUNRISE_END and time_of_day < SUNSET_START

View File

@@ -14,6 +14,7 @@ signal preset_changed(preset: SkyPreset)
@export var post_process_controller: PostProcessController
@export var vfx_controller: VFXController
@export var shadow_proxy_system: ShadowProxySystem
@export var weather_vfx: WeatherVFX
@export_group("Environment")
@export var world_environment: WorldEnvironment
@@ -34,6 +35,8 @@ signal preset_changed(preset: SkyPreset)
var _current_config: SkyConfig
var preset_name: String = ""
var _updating_preset_name: bool = false
var _debug_panel: SkyDebugPanel
var _debug_canvas_layer: CanvasLayer
func _ready() -> void:
@@ -41,9 +44,10 @@ func _ready() -> void:
_ensure_controllers_exist()
_connect_signals()
#property_list_changed_notify()
_sync_preset_name()
_apply_seed()
_ensure_post_process_environment()
_load_initial_preset()
notify_property_list_changed()
_sync_all_systems()
@@ -52,6 +56,8 @@ func _process(delta: float) -> void:
if show_debug_panel:
_update_debug_info()
elif _debug_panel != null:
_debug_panel.visible = false
func _ensure_controllers_exist() -> void:
@@ -90,6 +96,11 @@ func _ensure_controllers_exist() -> void:
shadow_proxy_system.name = "ShadowProxySystem"
add_child(shadow_proxy_system)
if weather_vfx == null:
weather_vfx = WeatherVFX.new()
weather_vfx.name = "WeatherVFX"
add_child(weather_vfx)
if world_environment == null:
_create_default_environment()
@@ -178,6 +189,7 @@ func _sync_all_systems() -> void:
_sync_clouds()
_sync_post_process()
_sync_shadows()
_sync_weather_vfx()
func _sync_sun_moon() -> void:
@@ -187,21 +199,48 @@ func _sync_sun_moon() -> void:
var sun_dir := day_night_controller.get_sun_direction()
var moon_dir := day_night_controller.get_moon_direction()
var sun_color: Color
var sun_energy: float
var moon_color: Color
var moon_energy: float
var ambient_color: Color
var ambient_energy: float
if _current_config:
sun_color = _current_config.sun_color
sun_energy = _current_config.sun_intensity
moon_color = _current_config.moon_color
moon_energy = _current_config.moon_intensity
ambient_color = _current_config.ambient_color
ambient_energy = _current_config.ambient_intensity
else:
sun_color = day_night_controller.get_sun_color()
sun_energy = day_night_controller.get_sun_intensity()
moon_color = day_night_controller.get_moon_color()
moon_energy = day_night_controller.get_moon_intensity()
ambient_color = day_night_controller.get_ambient_color()
ambient_energy = day_night_controller.get_ambient_intensity()
if weather_controller:
var wp := weather_controller.get_current_profile()
if wp:
ambient_color *= wp.ambient_color_multiplier
ambient_energy *= wp.ambient_intensity_multiplier
if sun_light:
sun_light.look_at(global_position - sun_dir, Vector3.UP)
sun_light.light_color = day_night_controller.get_sun_color()
sun_light.light_energy = day_night_controller.get_sun_intensity()
sun_light.visible = day_night_controller.get_sun_intensity() > 0.01
sun_light.light_color = sun_color
sun_light.light_energy = sun_energy
sun_light.visible = sun_energy > 0.01
if moon_light:
moon_light.look_at(global_position - moon_dir, Vector3.UP)
moon_light.light_color = day_night_controller.get_moon_color()
moon_light.light_energy = day_night_controller.get_moon_intensity()
moon_light.visible = day_night_controller.get_moon_intensity() > 0.01
moon_light.light_color = moon_color
moon_light.light_energy = moon_energy
moon_light.visible = moon_energy > 0.01
if world_environment and world_environment.environment:
world_environment.environment.ambient_light_color = day_night_controller.get_ambient_color()
world_environment.environment.ambient_light_energy = day_night_controller.get_ambient_intensity()
world_environment.environment.ambient_light_color = ambient_color
world_environment.environment.ambient_light_energy = ambient_energy
func _sync_clouds() -> void:
@@ -209,19 +248,39 @@ func _sync_clouds() -> void:
return
if day_night_controller:
var sun_color: Color
var sun_intensity: float
var moon_color: Color
var moon_intensity: float
if _current_config:
sun_color = _current_config.sun_color
sun_intensity = _current_config.sun_intensity
moon_color = _current_config.moon_color
moon_intensity = _current_config.moon_intensity
else:
sun_color = day_night_controller.get_sun_color()
sun_intensity = day_night_controller.get_sun_intensity()
moon_color = day_night_controller.get_moon_color()
moon_intensity = day_night_controller.get_moon_intensity()
cloud_system.set_sun_lighting(
day_night_controller.get_sun_direction(),
day_night_controller.get_sun_color(),
day_night_controller.get_sun_intensity()
sun_color,
sun_intensity
)
cloud_system.set_moon_lighting(
day_night_controller.get_moon_direction(),
day_night_controller.get_moon_color(),
day_night_controller.get_moon_intensity()
moon_color,
moon_intensity
)
if weather_controller:
cloud_system.global_coverage = weather_controller.get_cloud_coverage()
elif _current_config:
cloud_system.global_coverage = _current_config.cloud_coverage
if weather_controller:
cloud_system.set_global_wind(
weather_controller.get_wind_direction(),
weather_controller.get_wind_speed()
@@ -233,30 +292,23 @@ func _sync_post_process() -> void:
return
var sun_dir := day_night_controller.get_sun_direction()
var sun_color := day_night_controller.get_sun_color()
post_process_controller.set_sun_glow(
sun_dir,
sun_color,
day_night_controller.get_sun_intensity() * 0.5,
0.2
)
post_process_controller.set_fog_settings(
day_night_controller.get_fog_color(),
day_night_controller.get_fog_density()
)
var dawn_dusk_blend := 0.0
if day_night_controller.is_dawn() or day_night_controller.is_dusk():
dawn_dusk_blend = 1.0
post_process_controller.set_dawn_dusk_blend(dawn_dusk_blend)
post_process_controller.set_stars_visibility(
day_night_controller.get_stars_visibility()
)
if _current_config:
post_process_controller.set_sun_glow(
sun_dir,
_current_config.sun_color,
_current_config.sun_glow_intensity,
_current_config.sun_glow_size
)
post_process_controller.set_fog_settings(
_current_config.fog_color,
_current_config.fog_density
)
post_process_controller.set_dawn_dusk_blend(0.0)
post_process_controller.set_stars_visibility(
_current_config.stars_visibility,
_current_config.stars_tint
)
post_process_controller.set_sky_colors(
_current_config.sky_top_color,
_current_config.sky_horizon_color,
@@ -264,6 +316,34 @@ func _sync_post_process() -> void:
)
post_process_controller.gradient_intensity = _current_config.gradient_intensity
post_process_controller.apply_config(_current_config)
else:
var sun_color := day_night_controller.get_sun_color()
post_process_controller.set_sun_glow(
sun_dir,
sun_color,
day_night_controller.get_sun_intensity() * 0.5,
0.2
)
var fog_color := day_night_controller.get_fog_color()
var fog_density := day_night_controller.get_fog_density()
if weather_controller:
var wp := weather_controller.get_current_profile()
if wp:
fog_color *= wp.fog_color_multiplier
fog_density *= wp.fog_density_multiplier
post_process_controller.set_fog_settings(fog_color, fog_density)
var dawn_dusk_blend := 0.0
if day_night_controller.is_dawn() or day_night_controller.is_dusk():
dawn_dusk_blend = 1.0
post_process_controller.set_dawn_dusk_blend(dawn_dusk_blend)
post_process_controller.set_stars_visibility(
day_night_controller.get_stars_visibility()
)
post_process_controller.set_sky_colors(
day_night_controller.get_sky_top_color(),
day_night_controller.get_sky_horizon_color(),
day_night_controller.get_sky_bottom_color()
)
func _apply_preset_assets(preset: SkyPreset) -> void:
@@ -280,11 +360,20 @@ func _apply_preset_assets(preset: SkyPreset) -> void:
cloud_system.rebuild_layers()
func _resolve_preset_library() -> SkyboxPresetLibrary:
if preset_library != null:
return preset_library
if has_node(NodePath("PresetLibrary")):
return get_node(NodePath("PresetLibrary")) as SkyboxPresetLibrary
return null
func _get_property_list() -> Array:
var properties := []
var names: PackedStringArray = []
if preset_library:
names = preset_library.get_preset_names()
var lib := _resolve_preset_library()
if lib:
names = lib.get_preset_names()
var hint_string := ""
if names.size() > 0:
@@ -307,8 +396,13 @@ func _set(property: StringName, value: Variant) -> bool:
preset_name = value
if _updating_preset_name:
return true
if preset_library and String(preset_name) != "":
preset_library.apply_preset(String(preset_name))
var lib := _resolve_preset_library()
if lib and String(preset_name) != "":
lib.apply_preset(String(preset_name))
var p := lib.get_current_preset()
if p:
_on_preset_changed(p)
_sync_all_systems()
return true
return false
@@ -330,6 +424,25 @@ func _sync_preset_name() -> void:
_updating_preset_name = false
func _ensure_post_process_environment() -> void:
if post_process_controller and world_environment and world_environment.environment:
if post_process_controller.target_environment == null:
post_process_controller.target_environment = world_environment.environment
post_process_controller._setup_environment()
func _load_initial_preset() -> void:
if preset_library == null:
return
var current := preset_library.get_current_preset()
if current == null:
return
_sync_preset_name()
if current.config:
_current_config = current.config
_apply_preset_assets(current)
func _sync_shadows() -> void:
if shadow_proxy_system == null:
return
@@ -341,16 +454,47 @@ func _sync_shadows() -> void:
shadow_proxy_system.sync_with_cloud_system(cloud_system)
func _sync_weather_vfx() -> void:
if weather_vfx == null or weather_controller == null:
return
weather_vfx.set_rain_intensity(weather_controller.get_rain_intensity())
weather_vfx.set_snow_intensity(weather_controller.get_snow_intensity())
func _update_debug_info() -> void:
pass
if Engine.is_editor_hint():
return
if _debug_panel == null:
_create_debug_panel()
_debug_panel.visible = true
func _create_debug_panel() -> void:
_debug_canvas_layer = CanvasLayer.new()
_debug_canvas_layer.name = "DebugCanvasLayer"
_debug_canvas_layer.layer = 100
add_child(_debug_canvas_layer)
_debug_panel = SkyDebugPanel.new()
_debug_panel.name = "SkyDebugPanel"
_debug_panel.dynamic_sky = self
_debug_panel.anchor_left = 0.0
_debug_panel.anchor_top = 0.0
_debug_panel.anchor_right = 0.0
_debug_panel.anchor_bottom = 0.0
_debug_panel.offset_left = 10.0
_debug_panel.offset_top = 10.0
_debug_canvas_layer.add_child(_debug_panel)
func set_time_of_day(time: float) -> void:
_current_config = null
if day_night_controller:
day_night_controller.time_of_day = time
func set_weather(state: WeatherProfile.WeatherState, transition_time: float = -1.0) -> void:
_current_config = null
if weather_controller:
weather_controller.set_weather(state, transition_time)

View File

@@ -7,8 +7,15 @@ extends Control
var _panel: PanelContainer
var _vbox: VBoxContainer
var _time_label: Label
var _period_label: Label
var _preset_label: Label
var _weather_label: Label
var _sun_label: Label
var _moon_label: Label
var _ambient_label: Label
var _cloud_label: Label
var _fog_label: Label
var _rain_label: Label
var _seed_label: Label
var _time_slider: HSlider
var _weather_dropdown: OptionButton
@@ -50,10 +57,18 @@ func _create_ui() -> void:
_vbox.add_child(HSeparator.new())
_preset_label = Label.new()
_preset_label.text = "Preset: —"
_vbox.add_child(_preset_label)
_time_label = Label.new()
_time_label.text = "Time: 00:00 (0.00)"
_vbox.add_child(_time_label)
_period_label = Label.new()
_period_label.text = "Period: —"
_vbox.add_child(_period_label)
var time_hbox := HBoxContainer.new()
_vbox.add_child(time_hbox)
@@ -76,6 +91,20 @@ func _create_ui() -> void:
_vbox.add_child(HSeparator.new())
_sun_label = Label.new()
_sun_label.text = "Sun: —"
_vbox.add_child(_sun_label)
_moon_label = Label.new()
_moon_label.text = "Moon: —"
_vbox.add_child(_moon_label)
_ambient_label = Label.new()
_ambient_label.text = "Ambient: —"
_vbox.add_child(_ambient_label)
_vbox.add_child(HSeparator.new())
_weather_label = Label.new()
_weather_label.text = "Weather: Clear"
_vbox.add_child(_weather_label)
@@ -100,8 +129,16 @@ func _create_ui() -> void:
_cloud_label.text = "Clouds: 0%"
_vbox.add_child(_cloud_label)
_fog_label = Label.new()
_fog_label.text = "Fog: —"
_vbox.add_child(_fog_label)
_rain_label = Label.new()
_rain_label.text = "Rain: 0% | Snow: 0%"
_vbox.add_child(_rain_label)
_seed_label = Label.new()
_seed_label.text = "Seed: 0"
_seed_label.text = "Seed: 0 | Day: 1"
_vbox.add_child(_seed_label)
var meteor_button := Button.new()
@@ -120,6 +157,8 @@ func _update_labels() -> void:
if dynamic_sky == null:
return
_preset_label.text = "Preset: %s" % dynamic_sky.preset_name if dynamic_sky.preset_name != "" else "Preset: (none)"
var time := dynamic_sky.get_time_of_day()
var hours := int(time * 24.0)
var minutes := int(fmod(time * 24.0 * 60.0, 60.0))
@@ -128,6 +167,30 @@ func _update_labels() -> void:
if not _time_slider.has_focus():
_time_slider.set_value_no_signal(time)
if dynamic_sky.day_night_controller:
_period_label.text = "Period: %s" % dynamic_sky.day_night_controller.get_time_period().to_upper()
_pause_button.set_pressed_no_signal(dynamic_sky.day_night_controller.paused)
if dynamic_sky.sun_light:
_sun_label.text = "Sun: %.2f %s" % [
dynamic_sky.sun_light.light_energy,
"visible" if dynamic_sky.sun_light.visible else "hidden"
]
if dynamic_sky.moon_light:
_moon_label.text = "Moon: %.2f %s" % [
dynamic_sky.moon_light.light_energy,
"visible" if dynamic_sky.moon_light.visible else "hidden"
]
if dynamic_sky.world_environment and dynamic_sky.world_environment.environment:
var env := dynamic_sky.world_environment.environment
_ambient_label.text = "Ambient: %.2f" % env.ambient_light_energy
_fog_label.text = "Fog: %s density=%.4f" % [
"ON" if env.fog_enabled else "OFF",
env.fog_density
]
var weather := dynamic_sky.get_current_weather()
var weather_name: String = WeatherProfile.WeatherState.keys()[weather]
_weather_label.text = "Weather: %s" % weather_name
@@ -140,10 +203,15 @@ func _update_labels() -> void:
var progress := dynamic_sky.weather_controller.get_transition_progress()
_weather_label.text += " (transitioning %.0f%%)" % (progress * 100)
_seed_label.text = "Seed: %d" % dynamic_sky.deterministic_seed
if dynamic_sky.weather_controller:
var rain := dynamic_sky.weather_controller.get_rain_intensity()
var snow := dynamic_sky.weather_controller.get_snow_intensity()
_rain_label.text = "Rain: %d%% | Snow: %d%%" % [int(rain * 100), int(snow * 100)]
var day_num := 1
if dynamic_sky.day_night_controller:
_pause_button.set_pressed_no_signal(dynamic_sky.day_night_controller.paused)
day_num = dynamic_sky.day_night_controller.current_day
_seed_label.text = "Seed: %d | Day: %d" % [dynamic_sky.deterministic_seed, day_num]
func _on_time_slider_changed(value: float) -> void:

View File

@@ -207,10 +207,9 @@ func _create_star_trail(position: Vector3, direction: Vector3, is_meteor: bool =
mesh_instance.material_override = material
mesh_instance.position = position
add_child(mesh_instance)
mesh_instance.look_at(position + direction, Vector3.UP)
mesh_instance.rotate_object_local(Vector3.RIGHT, PI / 2.0)
add_child(mesh_instance)
return mesh_instance

View File

@@ -0,0 +1,246 @@
## Manages rain and snow particle effects driven by the weather controller.
@tool
class_name WeatherVFX
extends Node3D
@export_group("Rain")
@export var rain_amount: int = 4000
@export var rain_area: Vector3 = Vector3(80.0, 40.0, 80.0)
@export var rain_speed: float = 20.0
@export var rain_color: Color = Color(0.7, 0.75, 0.85, 0.4)
@export_group("Snow")
@export var snow_amount: int = 2000
@export var snow_area: Vector3 = Vector3(80.0, 30.0, 80.0)
@export var snow_speed: float = 3.0
@export var snow_color: Color = Color(0.95, 0.95, 1.0, 0.8)
@export_group("Lightning")
@export var lightning_color: Color = Color(0.9, 0.9, 1.0)
@export var lightning_flash_duration: float = 0.15
var _rain_particles: GPUParticles3D
var _snow_particles: GPUParticles3D
var _rain_material: ShaderMaterial
var _snow_material: ShaderMaterial
var _target_rain: float = 0.0
var _target_snow: float = 0.0
var _current_rain: float = 0.0
var _current_snow: float = 0.0
var _lightning_active: bool = false
var _lightning_frequency: float = 0.0
var _lightning_timer: float = 0.0
var _lightning_next: float = 0.0
var _lightning_flash_timer: float = 0.0
var _lightning_light: DirectionalLight3D
func _ready() -> void:
_create_rain_system()
_create_snow_system()
_create_lightning_light()
func _process(delta: float) -> void:
_current_rain = move_toward(_current_rain, _target_rain, delta * 0.5)
_current_snow = move_toward(_current_snow, _target_snow, delta * 0.3)
_rain_particles.emitting = _current_rain > 0.01
_rain_particles.amount = maxi(1, int(rain_amount * _current_rain))
if _rain_material:
_rain_material.set_shader_parameter("alpha_mult", _current_rain)
_snow_particles.emitting = _current_snow > 0.01
_snow_particles.amount = maxi(1, int(snow_amount * _current_snow))
if _snow_material:
_snow_material.set_shader_parameter("alpha_mult", _current_snow)
_process_lightning(delta)
_follow_camera()
func _process_lightning(delta: float) -> void:
if _lightning_flash_timer > 0.0:
_lightning_flash_timer -= delta
if _lightning_light:
var flash := _lightning_flash_timer / lightning_flash_duration
_lightning_light.light_energy = flash * 3.0
_lightning_light.visible = true
if _lightning_flash_timer <= 0.0 and _lightning_light:
_lightning_light.visible = false
if not _lightning_active or _lightning_frequency <= 0.0:
return
_lightning_timer += delta
if _lightning_timer >= _lightning_next:
_lightning_timer = 0.0
_lightning_next = randf_range(1.0 / maxf(_lightning_frequency, 0.01) * 0.5, 1.0 / maxf(_lightning_frequency, 0.01) * 2.0)
_trigger_lightning()
func _trigger_lightning() -> void:
_lightning_flash_timer = lightning_flash_duration
if _lightning_light:
_lightning_light.light_color = lightning_color
_lightning_light.light_energy = 3.0
_lightning_light.visible = true
_lightning_light.rotation_degrees.x = randf_range(-80.0, -50.0)
_lightning_light.rotation_degrees.y = randf_range(-180.0, 180.0)
func _create_lightning_light() -> void:
_lightning_light = DirectionalLight3D.new()
_lightning_light.name = "LightningFlash"
_lightning_light.light_color = lightning_color
_lightning_light.light_energy = 0.0
_lightning_light.shadow_enabled = false
_lightning_light.visible = false
add_child(_lightning_light)
func _follow_camera() -> void:
var vp := get_viewport()
if vp == null:
return
var cam := vp.get_camera_3d()
if cam:
global_position = cam.global_position
func set_rain_intensity(intensity: float) -> void:
_target_rain = clampf(intensity, 0.0, 1.0)
func set_snow_intensity(intensity: float) -> void:
_target_snow = clampf(intensity, 0.0, 1.0)
func set_lightning(active: bool, frequency: float = 0.1) -> void:
_lightning_active = active
_lightning_frequency = frequency
if not active and _lightning_light:
_lightning_light.visible = false
func _create_rain_system() -> void:
_rain_particles = GPUParticles3D.new()
_rain_particles.name = "RainParticles"
_rain_particles.amount = rain_amount
_rain_particles.lifetime = rain_area.y / rain_speed
_rain_particles.emitting = false
_rain_particles.visibility_aabb = AABB(-rain_area / 2.0, rain_area)
var mat := ParticleProcessMaterial.new()
mat.direction = Vector3(0.0, -1.0, 0.0)
mat.spread = 5.0
mat.initial_velocity_min = rain_speed * 0.8
mat.initial_velocity_max = rain_speed * 1.2
mat.gravity = Vector3(0.0, -9.8, 0.0)
mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_BOX
mat.emission_box_extents = Vector3(rain_area.x / 2.0, 0.5, rain_area.z / 2.0)
_rain_particles.process_material = mat
_rain_particles.transform.origin.y = rain_area.y / 2.0
_rain_material = ShaderMaterial.new()
_rain_material.shader = _get_rain_shader()
_rain_material.set_shader_parameter("rain_color", rain_color)
_rain_material.set_shader_parameter("alpha_mult", 0.0)
var mesh := QuadMesh.new()
mesh.size = Vector2(0.02, 0.6)
mesh.material = _rain_material
_rain_particles.draw_pass_1 = mesh
add_child(_rain_particles)
func _create_snow_system() -> void:
_snow_particles = GPUParticles3D.new()
_snow_particles.name = "SnowParticles"
_snow_particles.amount = snow_amount
_snow_particles.lifetime = snow_area.y / snow_speed * 2.5
_snow_particles.emitting = false
_snow_particles.visibility_aabb = AABB(-snow_area / 2.0, snow_area)
var mat := ParticleProcessMaterial.new()
mat.direction = Vector3(0.0, -1.0, 0.0)
mat.spread = 15.0
mat.initial_velocity_min = snow_speed * 0.5
mat.initial_velocity_max = snow_speed * 1.0
mat.gravity = Vector3(0.0, -1.0, 0.0)
mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_BOX
mat.emission_box_extents = Vector3(snow_area.x / 2.0, 0.5, snow_area.z / 2.0)
mat.turbulence_enabled = true
mat.turbulence_noise_strength = 2.0
mat.turbulence_noise_speed_random = 0.5
mat.turbulence_noise_scale = 4.0
_snow_particles.process_material = mat
_snow_particles.transform.origin.y = snow_area.y / 2.0
_snow_material = ShaderMaterial.new()
_snow_material.shader = _get_snow_shader()
_snow_material.set_shader_parameter("snow_color", snow_color)
_snow_material.set_shader_parameter("alpha_mult", 0.0)
var mesh := QuadMesh.new()
mesh.size = Vector2(0.08, 0.08)
mesh.material = _snow_material
_snow_particles.draw_pass_1 = mesh
add_child(_snow_particles)
func _get_rain_shader() -> Shader:
var shader := Shader.new()
shader.code = """
shader_type spatial;
render_mode unshaded, cull_disabled, depth_draw_opaque, blend_mix;
uniform vec4 rain_color : source_color = vec4(0.7, 0.75, 0.85, 0.4);
uniform float alpha_mult = 1.0;
void vertex() {
MODELVIEW_MATRIX = VIEW_MATRIX * mat4(
vec4(1.0, 0.0, 0.0, 0.0),
vec4(0.0, 1.0, 0.0, 0.0),
vec4(0.0, 0.0, 1.0, 0.0),
MODEL_MATRIX[3]
);
}
void fragment() {
float fade = smoothstep(0.0, 0.3, UV.y) * smoothstep(1.0, 0.7, UV.y);
ALBEDO = rain_color.rgb;
ALPHA = rain_color.a * fade * alpha_mult;
}
"""
return shader
func _get_snow_shader() -> Shader:
var shader := Shader.new()
shader.code = """
shader_type spatial;
render_mode unshaded, cull_disabled, depth_draw_opaque, blend_mix;
uniform vec4 snow_color : source_color = vec4(0.95, 0.95, 1.0, 0.8);
uniform float alpha_mult = 1.0;
void vertex() {
MODELVIEW_MATRIX = VIEW_MATRIX * mat4(
vec4(1.0, 0.0, 0.0, 0.0),
vec4(0.0, 1.0, 0.0, 0.0),
vec4(0.0, 0.0, 1.0, 0.0),
MODEL_MATRIX[3]
);
}
void fragment() {
float dist = length(UV - vec2(0.5));
float circle = smoothstep(0.5, 0.3, dist);
ALBEDO = snow_color.rgb;
ALPHA = snow_color.a * circle * alpha_mult;
}
"""
return shader

View File

@@ -0,0 +1 @@
uid://dgyy8274ji8vd