From c185fa9868e4a151be7a64bc030ce884c4396e81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Fri, 13 Feb 2026 17:51:23 -0300 Subject: [PATCH 1/5] Replace clouds shadow FX Replace the clouds overlay effect with a new implementation. See node editor descriptions or script comments for implementation details. --- .../fx/clouds_shadow/clouds_shadow.tscn | 45 ++++++++++++++ .../clouds_shadow/components/clouds_shadow.gd | 21 +++++++ .../components/clouds_shadow.gd.uid | 1 + .../components/clouds_shadow.gdshader | 61 +++++++++++++++++++ .../components/clouds_shadow.gdshader.uid | 1 + .../props/clouds_overlay/clouds_overlay.tscn | 37 ----------- .../components/clouds_overlay.gd | 52 ---------------- .../components/clouds_overlay.gd.uid | 1 - .../components/clouds_shadows.gdshader | 26 -------- .../components/clouds_shadows.gdshader.uid | 1 - 10 files changed, 129 insertions(+), 117 deletions(-) create mode 100644 scenes/game_elements/fx/clouds_shadow/clouds_shadow.tscn create mode 100644 scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gd create mode 100644 scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gd.uid create mode 100644 scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader create mode 100644 scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader.uid delete mode 100644 scenes/game_elements/props/clouds_overlay/clouds_overlay.tscn delete mode 100644 scenes/game_elements/props/clouds_overlay/components/clouds_overlay.gd delete mode 100644 scenes/game_elements/props/clouds_overlay/components/clouds_overlay.gd.uid delete mode 100644 scenes/game_elements/props/clouds_overlay/components/clouds_shadows.gdshader delete mode 100644 scenes/game_elements/props/clouds_overlay/components/clouds_shadows.gdshader.uid diff --git a/scenes/game_elements/fx/clouds_shadow/clouds_shadow.tscn b/scenes/game_elements/fx/clouds_shadow/clouds_shadow.tscn new file mode 100644 index 000000000..4704f60f3 --- /dev/null +++ b/scenes/game_elements/fx/clouds_shadow/clouds_shadow.tscn @@ -0,0 +1,45 @@ +[gd_scene format=3 uid="uid://c0374lgarm8gj"] + +[ext_resource type="Shader" uid="uid://blck4l5cl837d" path="res://scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader" id="1_02eyt"] +[ext_resource type="Script" uid="uid://8ayl2vtjam10" path="res://scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gd" id="1_vhj68"] + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_jw523"] +frequency = 0.0075 + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_02eyt"] +width = 168 +height = 256 +noise = SubResource("FastNoiseLite_jw523") +seamless = true +seamless_blend_skirt = 0.8 + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_2vvub"] +shader = ExtResource("1_02eyt") +shader_parameter/shadow_texture = SubResource("NoiseTexture2D_02eyt") +shader_parameter/amount = 0.35 +shader_parameter/contrast = 25.0 +shader_parameter/speed = Vector2(0.015, 0.01) +shader_parameter/alpha = 0.1 + +[node name="CloudsShadow" type="Parallax2D" unique_id=1515275591] +editor_description = "This Parallax2D node is used to repeat the texture so it's bigger than the viewport size. And to scroll it with the camera. +" +top_level = true +repeat_size = Vector2(1024, 1024) +repeat_times = 3 +script = ExtResource("1_vhj68") + +[node name="ColorRect" type="ColorRect" parent="." unique_id=1045851952] +unique_name_in_owner = true +editor_description = "Start with a small noise texture that is then upscaled to a square. The size of this ColorRect. + +The texture width is about 2/3 of its height to look flattened, matching the game perspective. This way the shadow seems to be projected on the ground. +" +material = SubResource("ShaderMaterial_2vvub") +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = 1024.0 +offset_bottom = 1024.0 +grow_horizontal = 2 +grow_vertical = 2 diff --git a/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gd b/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gd new file mode 100644 index 000000000..ba8cb9690 --- /dev/null +++ b/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gd @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: The Threadbare Authors +# SPDX-License-Identifier: MPL-2.0 +@tool +extends Parallax2D + +@export_tool_button("Random Clouds") var randomize_button: Callable = randomize + +var texture: NoiseTexture2D +var noise: FastNoiseLite + +@onready var color_rect: ColorRect = %ColorRect + + +func _ready() -> void: + texture = (color_rect.material as ShaderMaterial).get_shader_parameter("shadow_texture") + noise = texture.noise + + +func randomize() -> void: + noise.seed = randi() + await texture.changed diff --git a/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gd.uid b/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gd.uid new file mode 100644 index 000000000..3ec34ef45 --- /dev/null +++ b/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gd.uid @@ -0,0 +1 @@ +uid://8ayl2vtjam10 diff --git a/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader b/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader new file mode 100644 index 000000000..46f74ad3d --- /dev/null +++ b/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader @@ -0,0 +1,61 @@ +/** + * SPDX-FileCopyrightText: The Threadbare Authors + * SPDX-License-Identifier: MPL-2.0 + */ +shader_type canvas_item; + +/** + * The shader is set to substract because it's a shadow. + */ +render_mode blend_sub; + +/** + * Use a Simplex noise for a dynamic texture. Or provide your own grayscale tileable texture! + */ +uniform sampler2D shadow_texture: filter_nearest, repeat_enable; + +/** + * How much covered by clouds is the sky. + * - 0: Zero shadows. + * - 1: All dark. + * This parameter could be animated! + */ +uniform float amount: hint_range(0.0, 1.0) = 0.35; + +/** + * How much contrast. Or how much defined is the shadow silhouette. + */ +uniform float contrast: hint_range(0.0, 50.0) = 25.0; + +/** + * Animate the clouds. + * A 2/3 velocity emphasizes the world perspective. + */ +uniform vec2 speed = vec2(0.015,0.01); + +/** + * How much alpha. Keep this subtle. + */ +uniform float alpha: hint_range(0.0, 1.0) = 0.1; + + +void fragment() { + // Displace the UV to animate the shadow. + vec2 uv = UV + speed * TIME; + + float shadow = texture(shadow_texture, uv).r; + + // Add amount value. + shadow = amount + 0.5 - shadow; + + // Apply contrast to define the shadow silhouette. + // The result may be outside of the 0-1 range. + shadow = (shadow - 0.5) * contrast + 0.5; + + // Normalize the values to land between 0 and 1 again + // after applying contrast. + shadow = clamp(shadow, 0.0, 1.0); + + // Apply alpha. + COLOR.a = alpha * shadow; +} diff --git a/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader.uid b/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader.uid new file mode 100644 index 000000000..5bf68ebfa --- /dev/null +++ b/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader.uid @@ -0,0 +1 @@ +uid://blck4l5cl837d diff --git a/scenes/game_elements/props/clouds_overlay/clouds_overlay.tscn b/scenes/game_elements/props/clouds_overlay/clouds_overlay.tscn deleted file mode 100644 index ace81bfd7..000000000 --- a/scenes/game_elements/props/clouds_overlay/clouds_overlay.tscn +++ /dev/null @@ -1,37 +0,0 @@ -[gd_scene format=3 uid="uid://ci42ypvn5v8jr"] - -[ext_resource type="Shader" uid="uid://chgaevc31p1mn" path="res://scenes/game_elements/props/clouds_overlay/components/clouds_shadows.gdshader" id="1_l5uri"] -[ext_resource type="Script" uid="uid://bw0lg5yx4pxs2" path="res://scenes/game_elements/props/clouds_overlay/components/clouds_overlay.gd" id="2_gw00f"] - -[sub_resource type="Gradient" id="Gradient_l5uri"] -interpolation_mode = 1 -offsets = PackedFloat32Array(0, 0.74, 0.8, 1) -colors = PackedColorArray(0, 0, 0, 0, 0, 0, 0, 0.075, 0, 0, 0, 0.15, 0, 0, 0, 0.15) - -[sub_resource type="FastNoiseLite" id="FastNoiseLite_shbkg"] -fractal_lacunarity = 0.2 -fractal_gain = 0.0 -domain_warp_enabled = true - -[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_xa65i"] -resource_local_to_scene = true -width = 1920 -height = 1080 -noise = SubResource("FastNoiseLite_shbkg") -color_ramp = SubResource("Gradient_l5uri") -seamless = true - -[sub_resource type="ShaderMaterial" id="ShaderMaterial_shbkg"] -resource_local_to_scene = true -shader = ExtResource("1_l5uri") -shader_parameter/cloud_texture = SubResource("NoiseTexture2D_xa65i") -shader_parameter/offset = Vector2(0, 0) -shader_parameter/scale = 0.2 - -[node name="CloudsOverlay" type="ColorRect" unique_id=1716329843] -z_index = 10 -z_as_relative = false -material = SubResource("ShaderMaterial_shbkg") -offset_right = 1920.0 -offset_bottom = 1080.0 -script = ExtResource("2_gw00f") diff --git a/scenes/game_elements/props/clouds_overlay/components/clouds_overlay.gd b/scenes/game_elements/props/clouds_overlay/components/clouds_overlay.gd deleted file mode 100644 index a515aee53..000000000 --- a/scenes/game_elements/props/clouds_overlay/components/clouds_overlay.gd +++ /dev/null @@ -1,52 +0,0 @@ -# SPDX-FileCopyrightText: The Threadbare Authors -# SPDX-License-Identifier: MPL-2.0 -@tool -extends ColorRect - -@export var wind_direction: Vector2 = Vector2(1.0, 0.5) -@export_range(0, 50, 0.1) var wind_speed: float = 10 - -@export_range(0, 1, 0.01) var cloud_density: float = 0.2: - set(val): - cloud_density = val - update_noise_color_ramp() -@export_range(0, 1, 0.01) var cloud_fluffyness: float = 0.3: - set(val): - cloud_fluffyness = val - update_noise_color_ramp() -@export_range(0, 1, 0.01) var cloud_opacity: float = 0.15: - set(val): - cloud_opacity = val - update_noise_color_ramp() - -var current_offset: Vector2 = Vector2.ZERO - - -func _process(delta: float) -> void: - if not Engine.is_editor_hint(): - global_position = get_viewport().get_camera_2d().get_screen_center_position() - size / 2 - current_offset += wind_direction.normalized() * wind_speed * delta - material.set_shader_parameter("offset", current_offset) - - -func update_noise_color_ramp() -> void: - var new_color_ramp: Gradient = Gradient.new() - new_color_ramp.interpolation_mode = Gradient.GRADIENT_INTERPOLATE_CONSTANT - - new_color_ramp.set_color(0, Color(0, 0, 0, 0)) - new_color_ramp.set_color(1, Color(0, 0, 0, cloud_opacity)) - - var cloud_start_point = 1 - cloud_density - var cloud_end_point = cloud_start_point - cloud_fluffyness * (1 - cloud_start_point) - - new_color_ramp.add_point(cloud_start_point, Color(0, 0, 0, cloud_opacity)) - new_color_ramp.add_point(cloud_end_point, Color(0, 0, 0, cloud_opacity / 2)) - - var noise_texture: NoiseTexture2D = material.get_shader_parameter("cloud_texture") - noise_texture.color_ramp = new_color_ramp - - -func _notification(what: int) -> void: - match what: - NOTIFICATION_EDITOR_PRE_SAVE: - material.set_shader_parameter("offset", 0.0) diff --git a/scenes/game_elements/props/clouds_overlay/components/clouds_overlay.gd.uid b/scenes/game_elements/props/clouds_overlay/components/clouds_overlay.gd.uid deleted file mode 100644 index 74a185562..000000000 --- a/scenes/game_elements/props/clouds_overlay/components/clouds_overlay.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bw0lg5yx4pxs2 diff --git a/scenes/game_elements/props/clouds_overlay/components/clouds_shadows.gdshader b/scenes/game_elements/props/clouds_overlay/components/clouds_shadows.gdshader deleted file mode 100644 index 0b57fa883..000000000 --- a/scenes/game_elements/props/clouds_overlay/components/clouds_shadows.gdshader +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-FileCopyrightText: The Threadbare Authors -// SPDX-License-Identifier: MPL-2.0 -shader_type canvas_item; - -uniform sampler2D cloud_texture; -uniform sampler2D density_texture; - -uniform vec2 offset; - -uniform float scale: hint_range(0.1, 10.0, 0.1) = 1.0; - -varying vec2 world_pos; - -void vertex() { - // Transform it into world coordinates - world_pos = (MODEL_MATRIX * vec4(1.0, 1.0, 0.0, 1.0)).xy; -} - -vec2 to_uv_coordinates(vec2 position, sampler2D tex) { - ivec2 tex_size = textureSize(tex, 0); - return vec2(position.x / float(tex_size.x), position.y / float(tex_size.y)); -} - -void fragment() { - COLOR = texture(cloud_texture, fract((UV + to_uv_coordinates(world_pos, cloud_texture) + to_uv_coordinates(offset, cloud_texture)) * scale)); -} diff --git a/scenes/game_elements/props/clouds_overlay/components/clouds_shadows.gdshader.uid b/scenes/game_elements/props/clouds_overlay/components/clouds_shadows.gdshader.uid deleted file mode 100644 index 8b7beef55..000000000 --- a/scenes/game_elements/props/clouds_overlay/components/clouds_shadows.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://chgaevc31p1mn From db79216367ecd834f15aa3573eb0553c718cee90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Tue, 17 Feb 2026 10:21:52 -0300 Subject: [PATCH 2/5] Fray's End: Reinstate clouds --- scenes/world_map/frays_end.tscn | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scenes/world_map/frays_end.tscn b/scenes/world_map/frays_end.tscn index 0c9d8ba80..3928cd35d 100644 --- a/scenes/world_map/frays_end.tscn +++ b/scenes/world_map/frays_end.tscn @@ -52,6 +52,7 @@ [ext_resource type="PackedScene" uid="uid://vb5o7hh5an8j" path="res://scenes/game_elements/characters/npcs/elder/template_elder.tscn" id="43_ppslc"] [ext_resource type="PackedScene" uid="uid://c0104ickpm3ru" path="res://scenes/game_elements/props/decoration/flower/flower.tscn" id="45_cjmkx"] [ext_resource type="PackedScene" uid="uid://cr65lmm5b0ueo" path="res://scenes/game_elements/characters/npcs/cat/cat.tscn" id="52_ppslc"] +[ext_resource type="PackedScene" uid="uid://c0374lgarm8gj" path="res://scenes/game_elements/fx/clouds_shadow/clouds_shadow.tscn" id="54_ns5r3"] [ext_resource type="Script" uid="uid://cbj0406q05dly" path="res://scenes/game_elements/props/hint/input_key/interact_input.gd" id="55_wymun"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_h30yx"] @@ -1059,3 +1060,5 @@ shape = SubResource("RectangleShape2D_djq26") [node name="SpawnPointAfterIntro" parent="." unique_id=69976262 instance=ExtResource("37_thm8h")] position = Vector2(62, 1747) + +[node name="CloudsShadow" parent="." unique_id=1515275591 instance=ExtResource("54_ns5r3")] From 15de401377e9db5b65eb7271a7bfdbad962ff074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Tue, 17 Feb 2026 13:10:31 -0300 Subject: [PATCH 3/5] Update scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader Co-authored-by: Will Thompson --- .../fx/clouds_shadow/components/clouds_shadow.gdshader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader b/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader index 46f74ad3d..ce4a3e3fa 100644 --- a/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader +++ b/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader @@ -5,7 +5,7 @@ shader_type canvas_item; /** - * The shader is set to substract because it's a shadow. + * The shader is set to subtract because it's a shadow. */ render_mode blend_sub; From d56b714c9a8adf3fdc4fa0d177106253aafbef61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Tue, 17 Feb 2026 13:37:29 -0300 Subject: [PATCH 4/5] Update scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader Co-authored-by: Will Thompson --- .../fx/clouds_shadow/components/clouds_shadow.gdshader | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader b/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader index ce4a3e3fa..6b23ffc7e 100644 --- a/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader +++ b/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gdshader @@ -46,11 +46,11 @@ void fragment() { float shadow = texture(shadow_texture, uv).r; // Add amount value. - shadow = amount + 0.5 - shadow; + shadow = amount - shadow; // Apply contrast to define the shadow silhouette. // The result may be outside of the 0-1 range. - shadow = (shadow - 0.5) * contrast + 0.5; + shadow = shadow * contrast + 0.5; // Normalize the values to land between 0 and 1 again // after applying contrast. From 5ed7f5c5c0c8548d8e35fd15921783af9e9316a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Tue, 17 Feb 2026 14:06:26 -0300 Subject: [PATCH 5/5] Fixup: Persist random seed --- .../fx/clouds_shadow/components/clouds_shadow.gd | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gd b/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gd index ba8cb9690..59844023b 100644 --- a/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gd +++ b/scenes/game_elements/fx/clouds_shadow/components/clouds_shadow.gd @@ -5,17 +5,27 @@ extends Parallax2D @export_tool_button("Random Clouds") var randomize_button: Callable = randomize +@export var _seed: int: + set = _set_seed + var texture: NoiseTexture2D var noise: FastNoiseLite @onready var color_rect: ColorRect = %ColorRect +func _set_seed(new_seed: int) -> void: + _seed = new_seed + if noise: + noise.seed = _seed + await texture.changed + + func _ready() -> void: texture = (color_rect.material as ShaderMaterial).get_shader_parameter("shadow_texture") noise = texture.noise + _set_seed(_seed) func randomize() -> void: - noise.seed = randi() - await texture.changed + await _set_seed(randi())