update snow management
This commit is contained in:
Binary file not shown.
@@ -4,6 +4,15 @@ extends Node3D
|
|||||||
const NOISE_TEXTURE: Texture2D = preload("res://core/daynight/noise.tres")
|
const NOISE_TEXTURE: Texture2D = preload("res://core/daynight/noise.tres")
|
||||||
const WEATHER_SHADER: Material = preload("res://core/daynight/weather_overlay.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 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
|
@export var environment_config: EnvironmentConfig
|
||||||
|
|
||||||
@@ -157,9 +166,17 @@ func _restore_keyboard_action_events() -> void:
|
|||||||
_blocked_keyboard_events_by_action.clear()
|
_blocked_keyboard_events_by_action.clear()
|
||||||
|
|
||||||
func _on_tree_node_added(node: Node) -> void:
|
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)
|
_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:
|
func _queue_dynamic_environment_node(node: Node) -> void:
|
||||||
if not is_instance_valid(node):
|
if not is_instance_valid(node):
|
||||||
return
|
return
|
||||||
@@ -205,7 +222,7 @@ func _apply_dynamic_environment_materials(node: Node) -> void:
|
|||||||
if node.is_in_group("wind_node"):
|
if node.is_in_group("wind_node"):
|
||||||
_apply_wind_noise_to_node(node, NOISE_TEXTURE)
|
_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))
|
_apply_weather_overlay_to_node(node, _get_weather_overlay_material(node))
|
||||||
|
|
||||||
if _should_ignore_weather_overlay(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)
|
_apply_wind_noise_to_node(child, noise_tex)
|
||||||
|
|
||||||
func ApplyWeatherShaderToMaterials():
|
func ApplyWeatherShaderToMaterials():
|
||||||
for node in get_tree().get_nodes_in_group("weather_node"):
|
var current_scene := get_tree().current_scene
|
||||||
_apply_weather_overlay_to_node(node, _get_weather_overlay_material(node))
|
if current_scene != null:
|
||||||
|
_apply_weather_overlay_to_node(current_scene, _get_weather_overlay_material(current_scene))
|
||||||
for node in get_tree().get_nodes_in_group("weather_vegetables_node"):
|
|
||||||
_apply_weather_overlay_to_node(node, _get_weather_overlay_material(node))
|
|
||||||
|
|
||||||
func _get_weather_overlay_material(node: Node) -> Material:
|
func _get_weather_overlay_material(node: Node) -> Material:
|
||||||
if not node.is_in_group("weather_overlay_no_noise"):
|
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
|
return
|
||||||
|
|
||||||
if node is GeometryInstance3D:
|
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
|
node.material_overlay = null
|
||||||
else:
|
else:
|
||||||
node.material_overlay = material
|
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():
|
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:
|
func _clear_weather_overlay_from_node(node: Node) -> void:
|
||||||
if node is GeometryInstance3D:
|
if node is GeometryInstance3D:
|
||||||
@@ -289,11 +312,99 @@ func _geometry_uses_alpha_texture(node: GeometryInstance3D) -> bool:
|
|||||||
|
|
||||||
return false
|
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:
|
func _shader_material_uses_alpha_texture(material: ShaderMaterial) -> bool:
|
||||||
if material == null or material.shader == null:
|
if material == null or material.shader == null:
|
||||||
return false
|
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:
|
func _should_ignore_weather_overlay(node: Node) -> bool:
|
||||||
return node.is_in_group("weather_overlay_ignore")
|
return node.is_in_group("weather_overlay_ignore")
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ 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_START = 0.96;
|
||||||
const float LEAVES_FULL_SNOW_END = 0.86;
|
const float LEAVES_FULL_SNOW_END = 1.0;
|
||||||
|
const float LEAVES_TOP_SNOW_COVERAGE = 0.75;
|
||||||
|
|
||||||
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 +111,7 @@ void fragment() {
|
|||||||
float snow_amount = pow(get_snow_progress(), 0.55);
|
float snow_amount = pow(get_snow_progress(), 0.55);
|
||||||
|
|
||||||
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 * LEAVES_TOP_SNOW_COVERAGE, 1.08 - snow_amount * LEAVES_TOP_SNOW_COVERAGE, top_mask) * snow_visibility;
|
||||||
snow_mask *= step(0.01, snow_amount);
|
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 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);
|
||||||
|
|||||||
@@ -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_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_START = 0.58;
|
||||||
const float FULL_SNOW_VISUAL_END = 0.98;
|
const float FULL_SNOW_VISUAL_END = 0.86;
|
||||||
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;
|
||||||
@@ -154,7 +154,7 @@ void fragment() {
|
|||||||
float flat_accumulation = smoothstep(0.0, 0.35, v_snow_cap_mask) * snow_accumulation;
|
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_noise_mask = get_snow_noise_mask(world_pos, snow_progress);
|
||||||
float snow_variation = mix(0.75, 1.15, noise_val);
|
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_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));
|
||||||
|
|||||||
Reference in New Issue
Block a user