From f0964c811c11534a334217e06f5a4bc3469d475a Mon Sep 17 00:00:00 2001 From: TheThomaas Date: Thu, 22 Oct 2026 16:53:03 +0200 Subject: [PATCH] Add water section --- game/world/test_level.tscn | 57 +++++++++-- .../WaterMaker3D/CameraWaterOverlay.gdshader | 37 +++++++ .../CameraWaterOverlay.gdshader.uid | 1 + utils/WaterMaker3D/FogFade.gdshader | 24 +++++ utils/WaterMaker3D/FogFade.gdshader.uid | 1 + utils/WaterMaker3D/FogVolumeFadeScript.gd | 13 +++ utils/WaterMaker3D/FogVolumeFadeScript.gd.uid | 1 + utils/WaterMaker3D/WaterMaker3D.gd | 54 +++++++++++ utils/WaterMaker3D/WaterMaker3D.gd.uid | 1 + utils/WaterMaker3D/WaterMaker3D.tscn | 96 +++++++++++++++++++ 10 files changed, 278 insertions(+), 7 deletions(-) create mode 100644 utils/WaterMaker3D/CameraWaterOverlay.gdshader create mode 100644 utils/WaterMaker3D/CameraWaterOverlay.gdshader.uid create mode 100644 utils/WaterMaker3D/FogFade.gdshader create mode 100644 utils/WaterMaker3D/FogFade.gdshader.uid create mode 100644 utils/WaterMaker3D/FogVolumeFadeScript.gd create mode 100644 utils/WaterMaker3D/FogVolumeFadeScript.gd.uid create mode 100644 utils/WaterMaker3D/WaterMaker3D.gd create mode 100644 utils/WaterMaker3D/WaterMaker3D.gd.uid create mode 100644 utils/WaterMaker3D/WaterMaker3D.tscn diff --git a/game/world/test_level.tscn b/game/world/test_level.tscn index 347fe9a..f07a1df 100644 --- a/game/world/test_level.tscn +++ b/game/world/test_level.tscn @@ -17,6 +17,7 @@ [ext_resource type="Resource" uid="uid://dlhup2358q214" path="res://data/pokeapi/moves/screech.tres" id="13_tfb7h"] [ext_resource type="Resource" uid="uid://cn40f7a0djras" path="res://data/pokeapi/pokemon/0124_jynx.tres" id="14_2rm86"] [ext_resource type="Script" uid="uid://chqysfkk1prdb" path="res://game/pokemon/trainer_data.gd" id="15_htcyl"] +[ext_resource type="PackedScene" uid="uid://ca0wevg1lb4rx" path="res://utils/WaterMaker3D/WaterMaker3D.tscn" id="18_08mbr"] [sub_resource type="Environment" id="Environment_l60uw"] background_mode = 1 @@ -32,11 +33,43 @@ glow_enabled = true fog_enabled = true fog_light_color = Color(1, 1, 1, 1) fog_density = 0.001 +volumetric_fog_enabled = true +volumetric_fog_density = 0.0 [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_hh4m8"] albedo_texture = ExtResource("1_i3wuw") uv1_triplanar = true +[sub_resource type="FastNoiseLite" id="FastNoiseLite_08mbr"] +resource_local_to_scene = true + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_tfb7h"] +resource_local_to_scene = true +noise = SubResource("FastNoiseLite_08mbr") +seamless = true +as_normal_map = true + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_2rm86"] +resource_local_to_scene = true +noise = SubResource("FastNoiseLite_08mbr") +seamless = true +as_normal_map = true + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_htcyl"] +resource_local_to_scene = true +transparency = 1 +cull_mode = 2 +depth_draw_mode = 1 +albedo_color = Color(0.30980393, 0.5411765, 0.8666667, 0.3882353) +roughness = 0.0 +normal_enabled = true +normal_texture = SubResource("NoiseTexture2D_tfb7h") +refraction_enabled = true +refraction_texture = SubResource("NoiseTexture2D_2rm86") +uv1_scale = Vector3(0.04, 0.04, 0.04) +uv1_triplanar = true +uv1_world_triplanar = true + [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_5osju"] albedo_texture = ExtResource("2_rcccy") uv1_triplanar = true @@ -115,20 +148,30 @@ environment = SubResource("Environment_l60uw") [node name="map" type="Node3D" parent="." unique_id=2118568493] -[node name="floor" type="Node3D" parent="map" unique_id=1571459167] - -[node name="CSGBox3D" type="CSGBox3D" parent="map/floor" unique_id=1246319742] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0) +[node name="floor" type="CSGBox3D" parent="map" unique_id=1246319742] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10.50647, -5.586426, 0) material_override = SubResource("StandardMaterial3D_hh4m8") use_collision = true -size = Vector3(40, 1, 40) +size = Vector3(61.01294, 10.172852, 40) -[node name="CSGBox3D2" type="CSGBox3D" parent="map/floor" unique_id=406023419] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.35, 15.041) +[node name="water_area" type="CSGBox3D" parent="map/floor" unique_id=884797986] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -19.150932, 1.770874, 0) +material_override = SubResource("StandardMaterial3D_hh4m8") +operation = 2 +use_collision = true +size = Vector3(18.658081, 8.878174, 32.1709) + +[node name="battle_area" type="CSGBox3D" parent="map/floor" unique_id=406023419] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10.50647, 5.236426, 15.041) material_override = SubResource("StandardMaterial3D_hh4m8") use_collision = true size = Vector3(9, 0.3, 5) +[node name="WaterMaker3D" parent="map" unique_id=673111270 instance=ExtResource("18_08mbr")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -29.73397, -4.4205165, -0.010149956) +size = Vector3(19.148346, 7.7365723, 32.207764) +material = SubResource("StandardMaterial3D_htcyl") + [node name="box" type="CSGBox3D" parent="map" unique_id=498718915] transform = Transform3D(0.6727641, 0, -0.739857, 0, 1, 0, 0.739857, 0, 0.6727641, 3.424123, 0.049908042, 6.7458324) material_override = SubResource("StandardMaterial3D_5osju") diff --git a/utils/WaterMaker3D/CameraWaterOverlay.gdshader b/utils/WaterMaker3D/CameraWaterOverlay.gdshader new file mode 100644 index 0000000..cd22bfd --- /dev/null +++ b/utils/WaterMaker3D/CameraWaterOverlay.gdshader @@ -0,0 +1,37 @@ +shader_type canvas_item; + +uniform sampler2D screen_texture : hint_screen_texture; + +void fragment() { + vec2 uv = SCREEN_UV; + + // Ripple effect + float rippleSpeed = 1.5; + float rippleDensity = 10.0; + float rippleStrength = 0.02; + + // Calculate angle and distance from the center of the screen + vec2 center = vec2(0.5, 0.5); + vec2 delta = uv - center; + float distance = length(delta); + float angle = atan(delta.y, delta.x); + + // Apply the ripple effect + uv.x += cos(angle * rippleDensity + TIME * rippleSpeed) * rippleStrength * distance; + uv.y += sin(angle * rippleDensity + TIME * rippleSpeed) * rippleStrength * distance; + + // Simple blur effect + vec4 color = vec4(0.0); + float total = 0.0; + for (float x = -2.0; x <= 2.0; x++) { + for (float y = -2.0; y <= 2.0; y++) { + vec2 samplePos = uv + vec2(x, y) * 0.001; // Blur radius + color += texture(screen_texture, samplePos); + total += 1.0; + } + } + color /= total; + + // Output the final color + COLOR = color; +} diff --git a/utils/WaterMaker3D/CameraWaterOverlay.gdshader.uid b/utils/WaterMaker3D/CameraWaterOverlay.gdshader.uid new file mode 100644 index 0000000..e396310 --- /dev/null +++ b/utils/WaterMaker3D/CameraWaterOverlay.gdshader.uid @@ -0,0 +1 @@ +uid://co0evh1yuk11i diff --git a/utils/WaterMaker3D/FogFade.gdshader b/utils/WaterMaker3D/FogFade.gdshader new file mode 100644 index 0000000..e9b8cee --- /dev/null +++ b/utils/WaterMaker3D/FogFade.gdshader @@ -0,0 +1,24 @@ +shader_type fog; + +uniform float density : hint_range(0, 1, 0.0001) = 1.0; +uniform vec4 albedo : source_color = vec4(1.0); +uniform vec4 emission : source_color = vec4(0, 0, 0, 1); +uniform float height_falloff = 0.0; +uniform float edge_fade = 0.1; +uniform sampler3D density_texture: hint_default_white; +uniform vec4 fade_plane = vec4(0., 1., 0., -999.); + +void fog() { + DENSITY = density * clamp(exp2(-height_falloff * (WORLD_POSITION.y - OBJECT_POSITION.y)), 0.0, 1.0); + DENSITY *= texture(density_texture, UVW).r; + DENSITY *= pow(clamp(-2.0 * SDF / min(min(SIZE.x, SIZE.y), SIZE.z), 0.0, 1.0), edge_fade); + ALBEDO = albedo.rgb; + EMISSION = emission.rgb; + + // Anything above the fade plane will be drawn. Anything below has its density set to 0. + float fade_sharpness = 0.35; // Higher is faster fade + vec3 fade_plane_origin = fade_plane.xyz * fade_plane.w; + vec3 pos_rel_to_plane = WORLD_POSITION - fade_plane_origin; + float fade_mult = max(0., min(1., dot(pos_rel_to_plane, fade_plane.xyz) * fade_sharpness)); + DENSITY *= fade_mult * albedo.a; +} diff --git a/utils/WaterMaker3D/FogFade.gdshader.uid b/utils/WaterMaker3D/FogFade.gdshader.uid new file mode 100644 index 0000000..86546bc --- /dev/null +++ b/utils/WaterMaker3D/FogFade.gdshader.uid @@ -0,0 +1 @@ +uid://7a8yp0mgu34o diff --git a/utils/WaterMaker3D/FogVolumeFadeScript.gd b/utils/WaterMaker3D/FogVolumeFadeScript.gd new file mode 100644 index 0000000..5415b52 --- /dev/null +++ b/utils/WaterMaker3D/FogVolumeFadeScript.gd @@ -0,0 +1,13 @@ +extends FogVolume + +@export var fade_distance := 5 + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(_delta): + var cam = get_viewport().get_camera_3d() if get_viewport() else null + if cam: + var fade_plane_normal = cam.global_transform.basis.z * -1 + var fade_plane_pos = cam.global_transform.origin + cam.global_transform.basis.z * -fade_distance + var fade_plane_distance = fade_plane_pos.dot(fade_plane_normal) + var fade_plane = Vector4(fade_plane_normal.x, fade_plane_normal.y, fade_plane_normal.z, fade_plane_distance) + self.material.set_shader_parameter("fade_plane", fade_plane) diff --git a/utils/WaterMaker3D/FogVolumeFadeScript.gd.uid b/utils/WaterMaker3D/FogVolumeFadeScript.gd.uid new file mode 100644 index 0000000..173e3e2 --- /dev/null +++ b/utils/WaterMaker3D/FogVolumeFadeScript.gd.uid @@ -0,0 +1 @@ +uid://cshu5qhg3t5yc diff --git a/utils/WaterMaker3D/WaterMaker3D.gd b/utils/WaterMaker3D/WaterMaker3D.gd new file mode 100644 index 0000000..e8197a2 --- /dev/null +++ b/utils/WaterMaker3D/WaterMaker3D.gd @@ -0,0 +1,54 @@ +@tool +extends CSGBox3D + +@export var water_texture_move_speed := Vector3(0.0025, 0.0025, 0.0025) +@export var water_texture_uv_scale := 0.04 +@export var water_color := Color(0.3098039329052, 0.54117649793625, 0.86666667461395, 0.38823530077934) +@export var fog_color := Color(0, 0.04313725605607, 0.15686275064945) +@export_range(0.0, 250.0) var fog_fade_dist := 5.0 + +static var last_frame_drew_underwater_effect : int = -999 + +func _ready(): + self.process_priority = 999 # Call _process last to update move after any camera movement + +# Track the current camera with an area so we can check if it is inside the water +func should_draw_camera_underwater_effect(): + var camera := get_viewport().get_camera_3d() if get_viewport() else null + if not camera: return false + var aabb = self.global_transform * self.get_aabb().grow(0.025) + if not aabb.has_point(camera.global_position): return false + # Don't draw multiple overlays at once, incase 2 water bodies overlap + if last_frame_drew_underwater_effect == Engine.get_process_frames(): return false + + %CameraPosShapeCast3D.global_position = camera.global_position + %CameraPosShapeCast3D.force_shapecast_update() + var camera_is_in_water_area3d := false + for i in %CameraPosShapeCast3D.get_collision_count(): + if %CameraPosShapeCast3D.get_collider(i) == %SwimmableArea3D: + return true + return false + +func _update_mesh(): + if get_node_or_null("%CollisionShape3D"): + %CollisionShape3D.shape.size = self.size + +func _process(delta): + _update_mesh() + if self.material is StandardMaterial3D: + if not Engine.is_editor_hint(): + self.material.uv1_offset += water_texture_move_speed * delta + self.material.uv1_scale = Vector3(water_texture_uv_scale,water_texture_uv_scale,water_texture_uv_scale) + self.material.albedo_color = water_color + %FogVolume.material.set_shader_parameter("albedo", fog_color) + %FogVolume.material.set_shader_parameter("emission", fog_color) + %FogVolume.size = self.size + %FogVolume.fade_distance = self.fog_fade_dist + if not Engine.is_editor_hint(): + if should_draw_camera_underwater_effect(): + %WaterRippleOverlay.visible = true + %FogVolume.material.set_shader_parameter("edge_fade", 0.1) + last_frame_drew_underwater_effect = Engine.get_process_frames() + else: + %WaterRippleOverlay.visible = false + %FogVolume.material.set_shader_parameter("edge_fade", 1.1) diff --git a/utils/WaterMaker3D/WaterMaker3D.gd.uid b/utils/WaterMaker3D/WaterMaker3D.gd.uid new file mode 100644 index 0000000..aebe0c2 --- /dev/null +++ b/utils/WaterMaker3D/WaterMaker3D.gd.uid @@ -0,0 +1 @@ +uid://c6jwvpteq2e1k diff --git a/utils/WaterMaker3D/WaterMaker3D.tscn b/utils/WaterMaker3D/WaterMaker3D.tscn new file mode 100644 index 0000000..7b154f9 --- /dev/null +++ b/utils/WaterMaker3D/WaterMaker3D.tscn @@ -0,0 +1,96 @@ +[gd_scene load_steps=14 format=3 uid="uid://ca0wevg1lb4rx"] + +[ext_resource type="Script" path="res://utils/WaterMaker3D/WaterMaker3D.gd" id="1_7s6ww"] +[ext_resource type="Shader" path="res://utils/WaterMaker3D/FogFade.gdshader" id="2_5f01f"] +[ext_resource type="Shader" path="res://utils/WaterMaker3D/CameraWaterOverlay.gdshader" id="2_12cox"] +[ext_resource type="Script" path="res://utils/WaterMaker3D/FogVolumeFadeScript.gd" id="3_b5ytn"] + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_1bimf"] +resource_local_to_scene = true + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_mdx3j"] +resource_local_to_scene = true +seamless = true +as_normal_map = true +noise = SubResource("FastNoiseLite_1bimf") + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_xl6ub"] +resource_local_to_scene = true +seamless = true +as_normal_map = true +noise = SubResource("FastNoiseLite_1bimf") + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_gdho2"] +resource_local_to_scene = true +transparency = 1 +cull_mode = 2 +depth_draw_mode = 1 +albedo_color = Color(0.309804, 0.541176, 0.866667, 0.388235) +roughness = 0.0 +normal_enabled = true +normal_texture = SubResource("NoiseTexture2D_mdx3j") +refraction_enabled = true +refraction_texture = SubResource("NoiseTexture2D_xl6ub") +uv1_scale = Vector3(0.04, 0.04, 0.04) +uv1_triplanar = true +uv1_world_triplanar = true + +[sub_resource type="BoxShape3D" id="BoxShape3D_om5f8"] +resource_local_to_scene = true + +[sub_resource type="BoxShape3D" id="BoxShape3D_cfplo"] +size = Vector3(0.1, 0.1, 0.1) + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_wrt5a"] +resource_local_to_scene = true +shader = ExtResource("2_5f01f") +shader_parameter/density = 1.0 +shader_parameter/albedo = Color(0, 0.0431373, 0.156863, 1) +shader_parameter/emission = Color(0, 0.0431373, 0.156863, 1) +shader_parameter/height_falloff = 0.0 +shader_parameter/edge_fade = 0.1 +shader_parameter/fade_plane = Vector4(0, 1, 0, -999) + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_ccyp1"] +shader = ExtResource("2_12cox") + +[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_dcd7l"] + +[node name="WaterMaker3D" type="CSGBox3D"] +process_priority = 999 +material = SubResource("StandardMaterial3D_gdho2") +script = ExtResource("1_7s6ww") + +[node name="SwimmableArea3D" type="Area3D" parent="." groups=["water_area"]] +unique_name_in_owner = true + +[node name="CollisionShape3D" type="CollisionShape3D" parent="SwimmableArea3D"] +unique_name_in_owner = true +shape = SubResource("BoxShape3D_om5f8") + +[node name="CameraPosShapeCast3D" type="ShapeCast3D" parent="."] +unique_name_in_owner = true +shape = SubResource("BoxShape3D_cfplo") +target_position = Vector3(0, 0, 0) +collide_with_areas = true +collide_with_bodies = false + +[node name="FogVolume" type="FogVolume" parent="."] +unique_name_in_owner = true +size = Vector3(1, 1, 1) +material = SubResource("ShaderMaterial_wrt5a") +script = ExtResource("3_b5ytn") + +[node name="WaterRippleOverlay" type="TextureRect" parent="."] +unique_name_in_owner = true +visible = false +z_index = -10 +z_as_relative = false +material = SubResource("ShaderMaterial_ccyp1") +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +texture = SubResource("PlaceholderTexture2D_dcd7l")