diff --git a/addons/godotsteam/win64/~libgodotsteam.windows.template_debug.x86_64.dll b/addons/godotsteam/win64/~libgodotsteam.windows.template_debug.x86_64.dll new file mode 100644 index 0000000..2d345af Binary files /dev/null and b/addons/godotsteam/win64/~libgodotsteam.windows.template_debug.x86_64.dll differ diff --git a/core/daynight/environment_manager.gd b/core/daynight/environment_manager.gd index cb1d3d2..720a2fe 100644 --- a/core/daynight/environment_manager.gd +++ b/core/daynight/environment_manager.gd @@ -4,6 +4,15 @@ 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 = 32 #how many update of the environment (apply materials) will be done per frame +const FORCE_WEATHER_MATERIAL_PATH_PARTS: PackedStringArray = [ + "/chunk/material/field.tres", + "/chunk/material/grassflat_chunk.tres", + "/chunk/material/path_chunk.tres", + "/chunk/material/railway_chunk.tres", + "/chunk/material/terrain.tres", + "/chunk/prop/house/house.tres", + "/chunk/prop/house/house_emissiv.tres", +] @export var environment_config: EnvironmentConfig @@ -157,9 +166,17 @@ func _restore_keyboard_action_events() -> void: _blocked_keyboard_events_by_action.clear() 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"): + if _should_queue_dynamic_environment_node(node): _queue_dynamic_environment_node(node) +func _should_queue_dynamic_environment_node(node: Node) -> bool: + if node.is_in_group("wind_node"): + return true + if node.is_in_group("weather_vegetables_node"): + return true + + return node is Node3D + func _queue_dynamic_environment_node(node: Node) -> void: if not is_instance_valid(node): return @@ -205,7 +222,7 @@ func _apply_dynamic_environment_materials(node: Node) -> void: if node.is_in_group("wind_node"): _apply_wind_noise_to_node(node, NOISE_TEXTURE) - if node.is_in_group("weather_node") or node.is_in_group("weather_vegetables_node"): + if node is Node3D: _apply_weather_overlay_to_node(node, _get_weather_overlay_material(node)) if _should_ignore_weather_overlay(node): @@ -231,11 +248,9 @@ func _apply_wind_noise_to_node(node: Node, noise_tex: Texture2D) -> void: _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, _get_weather_overlay_material(node)) - - for node in get_tree().get_nodes_in_group("weather_vegetables_node"): - _apply_weather_overlay_to_node(node, _get_weather_overlay_material(node)) + var current_scene := get_tree().current_scene + if current_scene != null: + _apply_weather_overlay_to_node(current_scene, _get_weather_overlay_material(current_scene)) func _get_weather_overlay_material(node: Node) -> Material: if not node.is_in_group("weather_overlay_no_noise"): @@ -255,13 +270,21 @@ func _apply_weather_overlay_to_node(node: Node, material: Material) -> void: return if node is GeometryInstance3D: - if _should_clear_weather_overlay(node) or _geometry_uses_alpha_texture(node): + if _geometry_should_never_receive_weather_overlay(node): + node.material_overlay = null + elif _should_clear_weather_overlay(node) and not _geometry_forces_weather_overlay(node): + node.material_overlay = null + elif _geometry_uses_alpha_texture(node) or _geometry_should_skip_weather_overlay(node): node.material_overlay = null else: node.material_overlay = material + var child_material := _get_weather_overlay_material(node) + if child_material == WEATHER_SHADER and material == weather_shader_no_noise: + child_material = material + for child in node.get_children(): - _apply_weather_overlay_to_node(child, material) + _apply_weather_overlay_to_node(child, child_material) func _clear_weather_overlay_from_node(node: Node) -> void: if node is GeometryInstance3D: @@ -289,11 +312,99 @@ func _geometry_uses_alpha_texture(node: GeometryInstance3D) -> bool: return false +func _geometry_should_never_receive_weather_overlay(node: GeometryInstance3D) -> bool: + if node is GPUParticles3D: + return true + + var node_name := String(node.name).to_lower() + return node_name.contains("cloud") or node_name.contains("fog") or node_name.contains("godray") + +func _geometry_should_skip_weather_overlay(node: GeometryInstance3D) -> bool: + if _geometry_forces_weather_overlay(node): + return false + if _node_name_indicates_water(node): + return true + + var has_material: bool = false + var all_materials_ignored: bool = true + var material_override := node.material_override + if material_override != null: + has_material = true + all_materials_ignored = all_materials_ignored and _material_ignores_weather_overlay(material_override) + + if node is MeshInstance3D: + for surface_index in node.get_surface_override_material_count(): + var surface_material: Material = node.get_surface_override_material(surface_index) + if surface_material == null: + continue + + has_material = true + all_materials_ignored = all_materials_ignored and _material_ignores_weather_overlay(surface_material) + + if node.mesh: + for surface_index in node.mesh.get_surface_count(): + var mesh_material: Material = node.mesh.surface_get_material(surface_index) + if mesh_material == null: + continue + + has_material = true + all_materials_ignored = all_materials_ignored and _material_ignores_weather_overlay(mesh_material) + + return has_material and all_materials_ignored + +func _geometry_forces_weather_overlay(node: GeometryInstance3D) -> bool: + if _material_forces_weather_overlay(node.material_override): + return true + + if node is MeshInstance3D: + for surface_index in node.get_surface_override_material_count(): + if _material_forces_weather_overlay(node.get_surface_override_material(surface_index)): + return true + + if node.mesh: + for surface_index in node.mesh.get_surface_count(): + if _material_forces_weather_overlay(node.mesh.surface_get_material(surface_index)): + return true + + return false + +func _material_forces_weather_overlay(material: Material) -> bool: + if material == null: + return false + + var resource_path := material.resource_path.to_lower() + for path_part in FORCE_WEATHER_MATERIAL_PATH_PARTS: + if resource_path.contains(path_part): + return true + + return false + +func _node_name_indicates_water(node: Node) -> bool: + var node_name := String(node.name).to_lower() + return node_name.begins_with("water") or node_name.contains("/water") + +func _material_ignores_weather_overlay(material: Material) -> bool: + if material == null: + return false + + var resource_path := material.resource_path.to_lower() + if resource_path.contains("/water") or resource_path.contains("water_"): + return true + if resource_path.contains("/cloud/") or resource_path.contains("cloud"): + return true + + var base_material := material as BaseMaterial3D + if base_material != null: + return base_material.transparency != BaseMaterial3D.TRANSPARENCY_DISABLED or base_material.albedo_color.a < 0.99 + + return false + func _shader_material_uses_alpha_texture(material: ShaderMaterial) -> bool: if material == null or material.shader == null: return false - return material.shader.code.find("alpha_texture") != -1 + var shader_code := material.shader.code + return shader_code.find("alpha_texture") != -1 or shader_code.find("ALPHA") != -1 or shader_code.find("opacity") != -1 func _should_ignore_weather_overlay(node: Node) -> bool: return node.is_in_group("weather_overlay_ignore") diff --git a/core/daynight/tree_leaves.gdshader b/core/daynight/tree_leaves.gdshader index 74a1078..bf8ba4a 100644 --- a/core/daynight/tree_leaves.gdshader +++ b/core/daynight/tree_leaves.gdshader @@ -13,8 +13,9 @@ global uniform float global_snow_melt_speed = 0.1; global uniform float global_snow_amount = 0.0; global uniform vec4 global_snow_color; global uniform float global_rain_intensity; -const float LEAVES_FULL_SNOW_START = 0.58; -const float LEAVES_FULL_SNOW_END = 0.86; +const float LEAVES_FULL_SNOW_START = 0.96; +const float LEAVES_FULL_SNOW_END = 1.0; +const float LEAVES_TOP_SNOW_COVERAGE = 0.75; uniform sampler2D wind_noise : filter_linear_mipmap; uniform bool billboard_enabled = true; @@ -110,7 +111,7 @@ void fragment() { float snow_amount = pow(get_snow_progress(), 0.55); 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 * LEAVES_TOP_SNOW_COVERAGE, 1.08 - snow_amount * LEAVES_TOP_SNOW_COVERAGE, top_mask) * snow_visibility; snow_mask *= step(0.01, snow_amount); 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); diff --git a/core/daynight/weather_overlay.gdshader b/core/daynight/weather_overlay.gdshader index 62444cc..f4cccc1 100644 --- a/core/daynight/weather_overlay.gdshader +++ b/core/daynight/weather_overlay.gdshader @@ -17,8 +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_strength = 0.18; const float SNOW_VISUAL_RESPONSE = 0.55; -const float FULL_SNOW_VISUAL_START = 0.82; -const float FULL_SNOW_VISUAL_END = 0.98; +const float FULL_SNOW_VISUAL_START = 0.58; +const float FULL_SNOW_VISUAL_END = 0.86; uniform bool snow_noise_enabled = true; 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; @@ -154,7 +154,7 @@ void fragment() { 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(mix(snow_progress * 0.35, snow_progress * snow_variation, snow_noise_mask) + flat_accumulation * 0.15, 0.0, 1.0); + float snow_coverage = clamp(mix(snow_progress * 0.55, snow_progress * snow_variation, snow_noise_mask) + flat_accumulation * 0.2, 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 * mix(0.45, 0.9, snow_noise_mask));