show snow on grass

This commit is contained in:
2026-07-07 18:00:12 +02:00
parent 6da7021a58
commit 8ff14f3455
5 changed files with 58 additions and 18 deletions

View File

@@ -10,6 +10,7 @@ const TRACK_ZERO_SPACING_TARGET_RATIO: float = 0.97
const TRACK_ZERO_SPACING_MIN_DISTANCE: float = 1.0 const TRACK_ZERO_SPACING_MIN_DISTANCE: float = 1.0
enum TrainStartMode { RANDOM_POSITION, SPECIFIED_STATION, SPECIFIED_POSITION } enum TrainStartMode { RANDOM_POSITION, SPECIFIED_STATION, SPECIFIED_POSITION }
enum TrainFacingDirection { KEEP_PATH_DIRECTION, LOCOMOTIVE_LEFT, LOCOMOTIVE_RIGHT }
@export_group("Train") @export_group("Train")
##train speed ##train speed
@@ -46,6 +47,7 @@ enum TrainStartMode { RANDOM_POSITION, SPECIFIED_STATION, SPECIFIED_POSITION }
@export var train_start_delay_seconds: float = 0.0 @export var train_start_delay_seconds: float = 0.0
@export var train_start_after_delay: bool = true @export var train_start_after_delay: bool = true
@export var train_start_acceleration_seconds: float = 4.0 @export var train_start_acceleration_seconds: float = 4.0
@export_enum("keep_path_direction", "locomotive_left", "locomotive_right") var train_facing_direction: int = TrainFacingDirection.KEEP_PATH_DIRECTION
@export_group("Rails Bulding") @export_group("Rails Bulding")
##distance between sleepers of the rails ##distance between sleepers of the rails
@@ -103,6 +105,7 @@ var wagon_instances: Array[Node3D] = []
var wagon_progress_offsets: Array[float] = [] var wagon_progress_offsets: Array[float] = []
var _initial_is_inmotion: bool = true var _initial_is_inmotion: bool = true
var _is_photo_mode_active: bool = false var _is_photo_mode_active: bool = false
var _train_direction_sign: float = 1.0
func _ready() -> void: func _ready() -> void:
randomize() randomize()
@@ -144,8 +147,32 @@ func _apply_initial_train_start() -> void:
train_progress = wrapf(train_start_position, 0.0, total_length) train_progress = wrapf(train_start_position, 0.0, total_length)
_update_next_stop_index_from_progress() _update_next_stop_index_from_progress()
_apply_train_facing_direction(total_length)
_update_next_stop_index_from_progress()
_snap_train_to_progress() _snap_train_to_progress()
func _apply_train_facing_direction(total_length: float) -> void:
_train_direction_sign = 1.0
if train_facing_direction == TrainFacingDirection.KEEP_PATH_DIRECTION or curve == null:
return
if total_length <= 0.0:
return
var center_progress: float = wrapf(train_progress, 0.0, total_length)
var center_position: Vector3 = to_global(curve.sample_baked(center_progress, true))
var forward_progress: float = wrapf(center_progress + 2.0, 0.0, total_length)
var forward_position: Vector3 = to_global(curve.sample_baked(forward_progress, true))
var forward_direction: Vector3 = forward_position - center_position
if forward_direction.length_squared() <= 0.0001 or is_zero_approx(forward_direction.x):
return
var desired_x_sign: float = -1.0 if train_facing_direction == TrainFacingDirection.LOCOMOTIVE_LEFT else 1.0
if forward_direction.x * desired_x_sign < 0.0:
_train_direction_sign = -1.0
if not is_zero_approx(train_speed):
train_speed = absf(train_speed) * _train_direction_sign
func _apply_train_start_delay() -> void: func _apply_train_start_delay() -> void:
if not _initial_is_inmotion: if not _initial_is_inmotion:
return return
@@ -207,13 +234,9 @@ func _snap_train_to_progress() -> void:
train_progress = wrapf(train_progress, 0.0, total_length) train_progress = wrapf(train_progress, 0.0, total_length)
var center_position: Vector3 = to_global(curve.sample_baked(train_progress, true)) var center_position: Vector3 = to_global(curve.sample_baked(train_progress, true))
var prog_forward: float = wrapf(train_progress + 2.0, 0.0, total_length)
var forward_position: Vector3 = to_global(curve.sample_baked(prog_forward, true))
train_instance.global_position = center_position train_instance.global_position = center_position
if center_position.distance_to(forward_position) > 0.01: _orient_vehicle_to_track(train_instance, train_progress, total_length)
train_instance.look_at(forward_position, Vector3.UP)
train_instance.rotate_y(PI)
if cameras: if cameras:
cameras.global_position = center_position cameras.global_position = center_position
@@ -452,8 +475,7 @@ func train_move(delta: float) -> void:
if center_position.distance_to(forward_position) > 0.01: if center_position.distance_to(forward_position) > 0.01:
train_instance.global_position = center_position train_instance.global_position = center_position
train_instance.look_at(forward_position, Vector3.UP) _orient_vehicle_to_track(train_instance, train_progress, total_length)
train_instance.rotate_y(PI)
if cameras: if cameras:
cameras.global_position = center_position cameras.global_position = center_position
@@ -658,7 +680,7 @@ func _snap_wagons_to_progress(total_length: float = 0.0) -> void:
if i < wagon_progress_offsets.size(): if i < wagon_progress_offsets.size():
wagon_offset = wagon_progress_offsets[i] wagon_offset = wagon_progress_offsets[i]
var wagon_progress: float = train_progress - wagon_offset var wagon_progress: float = train_progress - wagon_offset * _train_direction_sign
var segment_spacing: float = maxf(wagon_offset - previous_wagon_offset, 0.1) var segment_spacing: float = maxf(wagon_offset - previous_wagon_offset, 0.1)
var vehicle_progress: float = wrapf(wagon_progress, 0.0, total_length) var vehicle_progress: float = wrapf(wagon_progress, 0.0, total_length)
@@ -670,18 +692,27 @@ func _snap_wagons_to_progress(total_length: float = 0.0) -> void:
vehicle_progress = _lerp_progress_on_track(vehicle_progress, corrected_progress, zero_spacing_fix_weight, total_length) vehicle_progress = _lerp_progress_on_track(vehicle_progress, corrected_progress, zero_spacing_fix_weight, total_length)
center_position = to_global(curve.sample_baked(vehicle_progress, true)) center_position = to_global(curve.sample_baked(vehicle_progress, true))
var prog_forward: float = wrapf(vehicle_progress + 2.0, 0.0, total_length)
var forward_position: Vector3 = to_global(curve.sample_baked(prog_forward, true))
wagon.global_position = center_position wagon.global_position = center_position
if center_position.distance_to(forward_position) > 0.01: _orient_vehicle_to_track(wagon, vehicle_progress, total_length)
wagon.look_at(forward_position, Vector3.UP)
wagon.rotate_y(PI)
previous_progress = vehicle_progress previous_progress = vehicle_progress
previous_position = center_position previous_position = center_position
previous_wagon_offset = wagon_offset previous_wagon_offset = wagon_offset
func _orient_vehicle_to_track(vehicle: Node3D, progress: float, total_length: float) -> void:
if vehicle == null or curve == null or total_length <= 0.0:
return
var center_progress: float = wrapf(progress, 0.0, total_length)
var center_position: Vector3 = to_global(curve.sample_baked(center_progress, true))
var forward_progress: float = wrapf(center_progress + 2.0 * _train_direction_sign, 0.0, total_length)
var forward_position: Vector3 = to_global(curve.sample_baked(forward_progress, true))
if center_position.distance_to(forward_position) <= 0.01:
return
vehicle.look_at(forward_position, Vector3.UP)
vehicle.rotate_y(PI)
func _get_zero_spacing_fix_weight(previous_progress: float, vehicle_progress: float, total_length: float) -> float: func _get_zero_spacing_fix_weight(previous_progress: float, vehicle_progress: float, total_length: float) -> float:
var distance_to_zero: float = minf( var distance_to_zero: float = minf(
_get_progress_distance_to_zero(previous_progress, total_length), _get_progress_distance_to_zero(previous_progress, total_length),
@@ -699,13 +730,13 @@ func _get_zero_spacing_target_distance(segment_spacing: float) -> float:
func _find_zero_spacing_progress(previous_progress: float, previous_position: Vector3, segment_spacing: float, minimum_distance: float, total_length: float) -> float: func _find_zero_spacing_progress(previous_progress: float, previous_position: Vector3, segment_spacing: float, minimum_distance: float, total_length: float) -> float:
var start_distance: float = minf(minimum_distance, segment_spacing) var start_distance: float = minf(minimum_distance, segment_spacing)
var best_progress: float = wrapf(previous_progress - start_distance, 0.0, total_length) var best_progress: float = wrapf(previous_progress - start_distance * _train_direction_sign, 0.0, total_length)
var search_limit: float = minf(maxf(segment_spacing, minimum_distance) + TRACK_ZERO_SPACING_SEARCH_EXTRA, total_length) var search_limit: float = minf(maxf(segment_spacing, minimum_distance) + TRACK_ZERO_SPACING_SEARCH_EXTRA, total_length)
var search_distance: float = start_distance var search_distance: float = start_distance
var previous_search_distance: float = start_distance var previous_search_distance: float = start_distance
while search_distance <= search_limit: while search_distance <= search_limit:
var candidate_progress: float = wrapf(previous_progress - search_distance, 0.0, total_length) var candidate_progress: float = wrapf(previous_progress - search_distance * _train_direction_sign, 0.0, total_length)
var candidate_position: Vector3 = to_global(curve.sample_baked(candidate_progress, true)) var candidate_position: Vector3 = to_global(curve.sample_baked(candidate_progress, true))
best_progress = candidate_progress best_progress = candidate_progress
if previous_position.distance_to(candidate_position) >= minimum_distance: if previous_position.distance_to(candidate_position) >= minimum_distance:

View File

@@ -15,6 +15,8 @@ global uniform float global_snow_melt_speed = 0.1;
global uniform float global_snow_amount = 0.0; global uniform float global_snow_amount = 0.0;
global uniform vec4 global_snow_color = vec4(0.92, 0.96, 1.0, 1.0); global uniform vec4 global_snow_color = vec4(0.92, 0.96, 1.0, 1.0);
global uniform float global_rain_intensity; global uniform float global_rain_intensity;
const float GRASS_FULL_SNOW_START = 0.58;
const float GRASS_FULL_SNOW_END = 0.86;
// --- PARAMETRI ESTETICI --- // --- PARAMETRI ESTETICI ---
uniform bool billboard_enabled = true; uniform bool billboard_enabled = true;
@@ -141,7 +143,7 @@ void fragment() {
float snow_mask = smoothstep(snow_start, 1.0, top_mask) * snow_amount * snow_visibility; float snow_mask = smoothstep(snow_start, 1.0, top_mask) * snow_amount * snow_visibility;
snow_mask *= step(0.01, snow_amount); snow_mask *= step(0.01, snow_amount);
snow_mask = clamp(snow_mask, 0.0, 1.0); snow_mask = clamp(snow_mask, 0.0, 1.0);
float full_snow_mask = smoothstep(0.72, 1.0, snow_amount) * step(0.01, snow_visibility); float full_snow_mask = smoothstep(GRASS_FULL_SNOW_START, GRASS_FULL_SNOW_END, snow_amount) * step(0.01, snow_visibility);
float final_snow_mask = max(snow_mask, full_snow_mask); float final_snow_mask = max(snow_mask, full_snow_mask);
vec3 snow_base_color = max(snow_color.rgb, global_snow_color.rgb); vec3 snow_base_color = max(snow_color.rgb, global_snow_color.rgb);

View File

@@ -13,6 +13,8 @@ global uniform float global_snow_melt_speed = 0.1;
global uniform float global_snow_amount = 0.0; global uniform float global_snow_amount = 0.0;
global uniform vec4 global_snow_color; global uniform vec4 global_snow_color;
global uniform float global_rain_intensity; global uniform float global_rain_intensity;
const float LEAVES_FULL_SNOW_START = 0.58;
const float LEAVES_FULL_SNOW_END = 0.86;
uniform sampler2D wind_noise : filter_linear_mipmap; uniform sampler2D wind_noise : filter_linear_mipmap;
uniform bool billboard_enabled = true; uniform bool billboard_enabled = true;
@@ -110,7 +112,7 @@ void fragment() {
float top_mask = 1.0 - shifted_uv.y; float top_mask = 1.0 - shifted_uv.y;
float snow_mask = smoothstep(1.0 - snow_amount * 1.35, 1.08 - snow_amount * 1.35, top_mask) * snow_visibility; float snow_mask = smoothstep(1.0 - snow_amount * 1.35, 1.08 - snow_amount * 1.35, top_mask) * snow_visibility;
snow_mask *= step(0.01, snow_amount); snow_mask *= step(0.01, snow_amount);
float full_snow_mask = smoothstep(0.78, 1.0, snow_amount) * clamp(snow_visibility, 0.0, 1.0); float full_snow_mask = smoothstep(LEAVES_FULL_SNOW_START, LEAVES_FULL_SNOW_END, snow_amount) * clamp(snow_visibility, 0.0, 1.0);
float final_snow_mask = max(snow_mask, full_snow_mask); float final_snow_mask = max(snow_mask, full_snow_mask);
float snow_light = mix(0.82, 1.0, max(v_shade_factor, 0.35)); float snow_light = mix(0.82, 1.0, max(v_shade_factor, 0.35));

View File

@@ -17,6 +17,8 @@ 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_scale = 0.22;
global uniform float global_snow_cap_noise_strength = 0.18; global uniform float global_snow_cap_noise_strength = 0.18;
const float SNOW_VISUAL_RESPONSE = 0.55; const float SNOW_VISUAL_RESPONSE = 0.55;
const float FULL_SNOW_VISUAL_START = 0.82;
const float FULL_SNOW_VISUAL_END = 0.98;
uniform bool snow_noise_enabled = true; uniform bool snow_noise_enabled = true;
uniform float snow_noise_scale : hint_range(0.01, 1.0) = 0.15; 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_edge_softness : hint_range(0.01, 0.5) = 0.2;
@@ -156,6 +158,8 @@ void fragment() {
float snow_factor = max(snow_edge * snow_coverage, flat_accumulation); float snow_factor = max(snow_edge * snow_coverage, flat_accumulation);
float snow_opacity = clamp(snow_factor, 0.0, 1.0); float snow_opacity = clamp(snow_factor, 0.0, 1.0);
snow_opacity = max(snow_opacity, flat_accumulation * mix(0.45, 0.9, snow_noise_mask)); snow_opacity = max(snow_opacity, flat_accumulation * mix(0.45, 0.9, snow_noise_mask));
float full_snow_opacity = snow_edge * smoothstep(FULL_SNOW_VISUAL_START, FULL_SNOW_VISUAL_END, snow_progress);
snow_opacity = max(snow_opacity, full_snow_opacity);
float shade = mix(-snow_color_variation, snow_color_variation, noise_val); 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); vec3 snow_albedo = clamp(global_snow_color.rgb + vec3(shade), 0.0, 1.0);

View File

@@ -324,6 +324,7 @@ train_start_mode = 2
train_start_stop_index = 0 train_start_stop_index = 0
train_start_position = 540.0 train_start_position = 540.0
train_start_after_delay = false train_start_after_delay = false
train_facing_direction = 2
sleepers_model = ExtResource("10_00nq7") sleepers_model = ExtResource("10_00nq7")
fireworks_scene = ExtResource("11_aylkj") fireworks_scene = ExtResource("11_aylkj")