improve snow

This commit is contained in:
2026-06-06 18:35:50 +02:00
parent 326d32c946
commit 9579f26a63
23 changed files with 168 additions and 69 deletions

View File

@@ -50,7 +50,7 @@ const RIVER_NEIGHBOUR_OFFSETS: Dictionary = {
#aumentare generazione a 3000 o 4000
#Se ci sono micro-scatti:
#abbassare generazione a 1000 o 1500
#Se i fili appaiono in ritardo:
"res://tgcc/chunk/railway/scene/chunk_railway_curve_2.tscn"#Se i fili appaiono in ritardo:
#aumentare wire a 1500 o 2000
#Se il cleanup causa scatti:
#abbassare cleanup a 500

View File

@@ -3,7 +3,7 @@ extends Node3D
const NOISE_TEXTURE: Texture2D = preload("res://core/daynight/noise.tres")
const WEATHER_SHADER: Material = preload("res://core/daynight/weather_overlay.tres")
const DYNAMIC_ENVIRONMENT_UPDATES_PER_FRAME: int = 2 #how many update of the environment (apply materials) will be done per frame
const DYNAMIC_ENVIRONMENT_UPDATES_PER_FRAME: int = 32 #how many update of the environment (apply materials) will be done per frame
@export var environment_config: EnvironmentConfig
@@ -80,6 +80,9 @@ func _ready() -> void:
func _process(_delta: float) -> void:
_process_pending_environment_nodes()
func flush_pending_environment_nodes() -> void:
_process_pending_environment_nodes(-1)
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"):
_queue_dynamic_environment_node(node)
@@ -108,10 +111,10 @@ func _queue_dynamic_environment_node(node: Node) -> void:
pending_environment_nodes[node.get_instance_id()] = node
func _process_pending_environment_nodes() -> void:
func _process_pending_environment_nodes(max_nodes: int = DYNAMIC_ENVIRONMENT_UPDATES_PER_FRAME) -> void:
var processed = 0
for node_id in pending_environment_nodes.keys():
if processed >= DYNAMIC_ENVIRONMENT_UPDATES_PER_FRAME:
if max_nodes >= 0 and processed >= max_nodes:
break
var node = pending_environment_nodes[node_id]

View File

@@ -7,6 +7,7 @@ global uniform float global_snow_melt_time = -1.0;
global uniform float global_snow_melt_speed = 0.1;
global uniform float global_snow_amount = 0.0;
global uniform vec4 global_snow_color = vec4(0.92, 0.96, 1.0, 1.0);
const float SNOW_VISUAL_RESPONSE = 0.55;
uniform float max_height : hint_range(0.02, 1.0) = 0.2;
uniform float half_width : hint_range(0.01, 20.0) = 1.0;
@@ -68,10 +69,14 @@ float get_snow_amount() {
return snow_amount;
}
float get_visual_snow_amount(float snow_amount) {
return pow(clamp(snow_amount, 0.0, 1.0), SNOW_VISUAL_RESPONSE);
}
void vertex() {
vec3 base_vertex = VERTEX;
vec3 world_pos = (MODEL_MATRIX * vec4(base_vertex, 1.0)).xyz;
float snow_amount = get_snow_amount();
float snow_amount = get_visual_snow_amount(get_snow_amount());
float noise_val = fbm(world_pos.xz * noise_scale);
float thickness = max_height * snow_amount * mix(
1.0 - noise_strength,

View File

@@ -3,6 +3,9 @@ extends Node
signal wind_parameters_changed(speed: float, strength: float, fade: float, direction: Vector2)
const SNOW_ACCUMULATION_DELAY: float = 4.0
const SNOW_ACCUMULATION_DELAY_THRESHOLD: float = 0.01
var thunder_audio_player: AudioStreamPlayer
var thunder_sounds: Array[AudioStream]
var rain_sounds: Array[AudioStream]
@@ -836,6 +839,8 @@ func toggle_snow(value: bool):
if is_snowing and is_raining:
toggle_rain(false)
var snow_accumulation_delay: float = _get_snow_accumulation_delay() if is_snowing else 0.0
# Fade particelle neve
if particles_snow:
@@ -849,7 +854,7 @@ func toggle_snow(value: bool):
snow_particles_tween = create_tween()
snow_particles_tween.tween_property(particles_snow, "amount_ratio", 1.0, environment_config.snow_fade_time)
start_snow_accumulation()
start_snow_accumulation(snow_accumulation_delay)
else:
snow_particles_tween = create_tween()
snow_particles_tween.tween_property(particles_snow, "amount_ratio", 0.0, environment_config.snow_fade_time)
@@ -864,6 +869,8 @@ func toggle_snow(value: bool):
snow_weather_tween.kill()
var snow_amount_transition_duration: float = _get_snow_amount_transition_duration(is_snowing)
snow_tween = create_tween()
if is_snowing and snow_accumulation_delay > 0.0:
snow_tween.tween_interval(snow_accumulation_delay)
snow_tween.tween_method(
init_snow_amount,
actual_snow_amount,
@@ -928,14 +935,26 @@ func init_snow_amount(value: float):
func init_snow_weather_amount(value: float):
snow_weather_amount = value
func start_snow_accumulation() -> void:
func start_snow_accumulation(delay: float = 0.0) -> 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)
RenderingServer.global_shader_parameter_set("global_snow_start_time", Time.get_ticks_msec() / 1000.0 + delay)
_flush_pending_weather_materials()
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)
func _get_snow_accumulation_delay() -> float:
if actual_snow_amount > SNOW_ACCUMULATION_DELAY_THRESHOLD:
return 0.0
return SNOW_ACCUMULATION_DELAY
func _flush_pending_weather_materials() -> void:
var environment_manager := get_parent()
if environment_manager != null and environment_manager.has_method("flush_pending_environment_nodes"):
environment_manager.call("flush_pending_environment_nodes")
func _get_snow_amount_transition_duration(is_accumulating: bool) -> float:
if environment_config == null:
return 0.0

View File

@@ -16,6 +16,7 @@ global uniform float global_snow_cap_flatness_start = 0.72;
global uniform float global_snow_cap_flatness_end = 0.96;
global uniform float global_snow_cap_noise_scale = 0.22;
global uniform float global_snow_cap_noise_strength = 0.18;
const float SNOW_VISUAL_RESPONSE = 0.55;
uniform float snow_noise_scale : hint_range(0.01, 1.0) = 0.15;
uniform float snow_edge_softness : hint_range(0.01, 0.5) = 0.2;
uniform float snow_roughness_variation : hint_range(0.0, 0.3) = 0.15;
@@ -86,6 +87,18 @@ float get_snow_progress() {
return snow_progress;
}
float get_visual_snow_progress(float snow_progress) {
return pow(clamp(snow_progress, 0.0, 1.0), SNOW_VISUAL_RESPONSE);
}
float get_snow_noise_mask(vec3 world_pos, float snow_progress) {
float detail_noise = texture(noise_texture, world_pos.xz * snow_noise_scale).r;
float broad_noise = texture(noise_texture, world_pos.xz * snow_noise_scale * 0.35 + vec2(19.1, 7.4)).r;
float combined_noise = mix(detail_noise, broad_noise, 0.35);
float threshold = mix(0.92, 0.08, snow_progress);
return smoothstep(threshold - 0.18, threshold + 0.18, combined_noise);
}
float ripple_ring(vec2 uv, float time_offset) {
float d = length(uv);
float ring = sin(d * 30.0 - TIME * ripple_speed + time_offset) * 0.5 + 0.5;
@@ -94,7 +107,7 @@ float ripple_ring(vec2 uv, float time_offset) {
}
void vertex() {
float snow_progress = get_snow_progress();
float snow_progress = get_visual_snow_progress(get_snow_progress());
float snow_accumulation = snow_progress * global_snow_max_accumulation;
vec3 world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
vec3 world_normal = normalize((MODEL_MATRIX * vec4(NORMAL, 0.0)).xyz);
@@ -104,7 +117,7 @@ void vertex() {
global_snow_cap_flatness_end,
world_normal.y
);
float accumulation_growth = smoothstep(0.08, 0.65, snow_progress);
float accumulation_growth = smoothstep(0.02, 0.45, snow_progress);
float cap_noise = fbm(world_pos.xz * global_snow_cap_noise_scale + vec2(11.3, 4.7));
float cap_variation = mix(1.0 - global_snow_cap_noise_strength, 1.0 + global_snow_cap_noise_strength, cap_noise);
@@ -118,6 +131,8 @@ void fragment() {
vec3 world_pos = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
vec3 world_normal = normalize((INV_VIEW_MATRIX * vec4(NORMAL, 0.0)).xyz);
float facing_up = clamp(world_normal.y, 0.0, 1.0);
vec3 geometric_normal = normalize(cross(dFdx(world_pos), dFdy(world_pos)));
float snow_facing_up = max(facing_up, abs(geometric_normal.y));
float noise_val = texture(noise_texture, world_pos.xz * snow_noise_scale).r;
//Snow
@@ -127,14 +142,15 @@ void fragment() {
float snow_edge = smoothstep(
global_snow_threshold - snow_edge_softness,
global_snow_threshold + snow_edge_softness,
facing_up
snow_facing_up
);
float flat_accumulation = smoothstep(0.0, 0.35, v_snow_cap_mask) * snow_accumulation;
float snow_noise_mask = get_snow_noise_mask(world_pos, snow_progress);
float snow_variation = mix(0.75, 1.15, noise_val);
float snow_coverage = clamp(snow_progress * snow_variation + flat_accumulation * 0.25, 0.0, 1.0);
float snow_coverage = clamp(mix(snow_progress * 0.35, snow_progress * snow_variation, snow_noise_mask) + flat_accumulation * 0.15, 0.0, 1.0);
float snow_factor = max(snow_edge * snow_coverage, flat_accumulation);
float snow_opacity = clamp(snow_factor, 0.0, 1.0);
snow_opacity = max(snow_opacity, flat_accumulation * 0.9);
snow_opacity = max(snow_opacity, flat_accumulation * mix(0.45, 0.9, snow_noise_mask));
float shade = mix(-snow_color_variation, snow_color_variation, noise_val);
vec3 snow_albedo = clamp(global_snow_color.rgb + vec3(shade), 0.0, 1.0);

View File

@@ -1,6 +1,7 @@
[gd_resource type="ShaderMaterial" format=3 uid="uid://cn5vw7unbqgve"]
[ext_resource type="Shader" uid="uid://dh3j2jp6defuk" path="res://core/daynight/weather_overlay.gdshader" id="1_weather"]
[ext_resource type="Texture2D" uid="uid://bpswbjh4jj1ou" path="res://core/daynight/noise.tres" id="2_noise"]
[resource]
render_priority = 0
@@ -19,3 +20,4 @@ shader_parameter/wet_roughness = 0.05
shader_parameter/rain_normal_strength = 0.4
shader_parameter/puddle_noise_scale = 0.08
shader_parameter/puddle_threshold = 0.45
shader_parameter/noise_texture = ExtResource("2_noise")

View File

@@ -8,7 +8,9 @@ global uniform float global_snow_melt_time = -1.0;
global uniform float global_snow_melt_speed = 0.1;
global uniform float global_snow_amount = 0.0;
global uniform vec4 global_snow_color;
const float SNOW_VISUAL_RESPONSE = 0.55;
uniform float snow_edge_softness : hint_range(0.01, 0.5) = 0.15;
uniform float snow_noise_scale : hint_range(0.01, 1.0) = 0.15;
uniform float snow_color_variation : hint_range(0.0, 0.15) = 0.05;
@@ -50,6 +52,18 @@ float get_snow_progress() {
return snow_progress;
}
float get_visual_snow_progress(float snow_progress) {
return pow(clamp(snow_progress, 0.0, 1.0), SNOW_VISUAL_RESPONSE);
}
float get_snow_noise_mask(vec3 world_pos, float snow_progress) {
float detail_noise = texture(noise_texture, world_pos.xz * snow_noise_scale).r;
float broad_noise = texture(noise_texture, world_pos.xz * snow_noise_scale * 0.35 + vec2(19.1, 7.4)).r;
float combined_noise = mix(detail_noise, broad_noise, 0.35);
float threshold = mix(0.92, 0.08, snow_progress);
return smoothstep(threshold - 0.18, threshold + 0.18, combined_noise);
}
void fragment() {
vec3 world_pos = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
@@ -57,14 +71,15 @@ void fragment() {
float facing_up = 1.0;
// Snow accumulation
float snow_amount = get_snow_progress();
float snow_amount = get_visual_snow_progress(get_snow_progress());
// Plain surfaces fade in uniformly to avoid patchy strip-like accumulation.
float snow_mask = smoothstep(0.0, 1.0, snow_amount);
// Plain surfaces accumulate through world-space noise so flat snow is not uniform.
float snow_noise_mask = get_snow_noise_mask(world_pos, snow_amount);
float snow_mask = mix(snow_amount * 0.35, snow_amount, snow_noise_mask);
snow_mask *= step(0.01, snow_amount);
// Snow color with slight variation
float shade = fract(sin(dot(UV, vec2(12.9898, 78.233))) * 43758.5453);
float shade = texture(noise_texture, world_pos.xz * snow_noise_scale * 2.0 + vec2(3.7, 11.2)).r;
shade = mix(-snow_color_variation, snow_color_variation, shade);
vec3 snow_albedo = clamp(global_snow_color.rgb + vec3(shade), 0.0, 1.0);

View File

@@ -7,6 +7,7 @@
render_priority = 0
shader = ExtResource("1_weather_plain")
shader_parameter/snow_edge_softness = 0.15
shader_parameter/snow_noise_scale = 0.15
shader_parameter/snow_color_variation = 0.05
shader_parameter/ripple_scale = 1.5
shader_parameter/ripple_speed = 2.0

View File

@@ -167,7 +167,7 @@ extends Resource
@export var snow_threshold: float = 0.4 #Normal Y threshold for snow accumulation on surfaces
@export var snow_accumulation_speed: float = 0.005 #Accumulation speed: 0.005 -> ~200s, 0.01 -> 100s, 0.02 -> 50s
@export var snow_melt_speed: float = 0.05 #Speed at which accumulated snow melts away
@export var show_snow_accumulation_volume: bool = true #Enables vertex snow buildup; when false snow only changes surface color
@export var show_snow_accumulation_volume: bool = false #Enables vertex snow buildup; when false snow only changes surface color
@export var snow_max_accumulation: float = 0.25 #Maximum accumulated snow factor applied to coverage and thickness
@export var snow_color: Color = Color(0.9, 0.95, 1.0) #Albedo color of snow on surfaces
@export var snow_cap_height: float = 0.03 #Maximum snow thickness extruded on flat surfaces