Files
tgcc/core/daynight/environment_manager.gd
2026-04-24 12:22:46 +02:00

161 lines
5.3 KiB
GDScript

class_name EnvironmentManagerRoot
extends Node3D
const NOISE_TEXTURE: Texture2D = preload("res://core/daynight/noise.tres")
const WEATHER_SHADER: Material = preload("res://core/daynight/weather_overlay.tres")
const WEATHER_PLAIN_SHADER: Material = preload("res://core/daynight/weather_plain_shader.tres")
@export var environment_config: EnvironmentConfig
@export_group("Camera")
@export var camera: Camera3D
@export var camera_pivot: Node3D
@export_group("Particles")
@export var particles_wind: GPUParticles3D
@export var particles_snow: GPUParticles3D
@export var particles_fireflies: GPUParticles3D
@export var particles_rain: GPUParticles3D
@export var godray: PackedScene
@export var environment_dust: ColorRect
@export var blur: ColorRect
@export var environment_shadows: MeshInstance3D
@export_group("Sound")
@export var thunder_sounds: Array[AudioStream]
@export var rain_sounds: Array[AudioStream]
#environment nodes
@onready var sun: DirectionalLight3D = $"../DirectionalLight3D"
@onready var environment: WorldEnvironment = $"../WorldEnvironment"
var day_night_controller: DayNightController
var weather_controller: WeatherController
var day_tween: Tween
var day_time: float = 0.0
func _ready() -> void:
#connect shader when new node is added
get_tree().node_added.connect(_on_tree_node_added)
#set noise texture 2d to materials in special group
ApplyWindNoiseToMaterials()
#set weather overlay (snow + rain) to materials in special group
ApplyWeatherShaderToMaterials()
if day_night_controller == null:
day_night_controller = DayNightController.new(
environment_config
)
day_night_controller.name = "DayNightController"
day_night_controller.time_changed.connect(select_day_time)
add_child(day_night_controller)
if weather_controller == null:
weather_controller = WeatherController.new(
particles_wind,
particles_snow,
particles_fireflies,
particles_rain,
godray,
environment_dust,
blur,
environment_shadows,
sun,
environment,
environment_config,
camera,
camera_pivot,
thunder_sounds,
rain_sounds
)
weather_controller.name = "WeatherController"
add_child(weather_controller)
func _on_tree_node_added(node: Node) -> void:
if node.is_in_group("wind_node") or node.is_in_group("weather_node") or node.is_in_group("weather_vegetables_node"):
call_deferred("_apply_dynamic_environment_materials", node)
func _apply_dynamic_environment_materials(node: Node) -> void:
if not is_instance_valid(node):
return
if node.is_in_group("wind_node"):
_apply_wind_noise_to_node(node, NOISE_TEXTURE)
if node.is_in_group("weather_node"):
_apply_weather_overlay_to_node(node, WEATHER_SHADER)
if node.is_in_group("weather_vegetables_node"):
_apply_weather_overlay_to_node(node, WEATHER_PLAIN_SHADER)
func ApplyWindNoiseToMaterials():
for node in get_tree().get_nodes_in_group("wind_node"):
_apply_wind_noise_to_node(node, NOISE_TEXTURE)
func _apply_wind_noise_to_node(node: Node, noise_tex: Texture2D) -> void:
if node is GeometryInstance3D:
var material_override := node.material_override as ShaderMaterial
if material_override:
material_override.set_shader_parameter("wind_noise", noise_tex)
if node is MeshInstance3D:
for surface_index in node.get_surface_override_material_count():
var surface_material := node.get_surface_override_material(surface_index) as ShaderMaterial
if surface_material:
surface_material.set_shader_parameter("wind_noise", noise_tex)
for child in node.get_children():
_apply_wind_noise_to_node(child, noise_tex)
func ApplyWeatherShaderToMaterials():
for node in get_tree().get_nodes_in_group("weather_node"):
_apply_weather_overlay_to_node(node, WEATHER_SHADER)
for node in get_tree().get_nodes_in_group("weather_vegetables_node"):
_apply_weather_overlay_to_node(node, WEATHER_PLAIN_SHADER)
func _apply_weather_overlay_to_node(node: Node, material: Material) -> void:
if node is GeometryInstance3D:
node.material_overlay = material
for child in node.get_children():
_apply_weather_overlay_to_node(child, material)
func select_day_time(normalized_time: float) -> void:
#set show_day_time_debug = true to show debug on screen
#normalized_time is a value between 0 and 1; the time of the day is calculate as "normalized_time" * 1440; day_time is the step to pass from sunrise, to day, to sunset, to night
#e.g.
#Time normalized_time day_time
#00:00 0.0000 3.0
#06:00 0.2500 1.0
#09:36 0.4000 1.75
#10:48 0.4500 2.0
#12:00 0.5000 2.0
#19:12 0.8000 2.0
#21:36 0.9000 2.5
#24:00 1.0000 3.0
if normalized_time < environment_config.sunrise:
#Sunrise: night → morning
day_time = 3.0 - (normalized_time / environment_config.sunrise) * 2.0 # 3.0 → 1.0
elif normalized_time < environment_config.day:
#Morning: morning → afternoon
var t: float = (normalized_time - environment_config.sunrise) / (environment_config.day - environment_config.sunrise)
day_time = 1.0 + t # 1.0 → 2.0
elif normalized_time < environment_config.sunset:
#Broad daylight
day_time = 2.0
elif normalized_time < environment_config.night:
#Sunset: afternoon → night
var t: float = (normalized_time - environment_config.sunset) / (environment_config.night - environment_config.sunset)
day_time = 2.0 + t # 2.0 → 3.0
else:
#Night
day_time = 3.0
if weather_controller:
weather_controller.day_time = day_time