From f98773237e90d04ab72783876b346a73fb0d5691 Mon Sep 17 00:00:00 2001 From: Dan Baker Date: Tue, 1 Jul 2025 10:32:21 +0100 Subject: [PATCH] Implements tree visibility occlusion system. Adds tree fading based on camera line of sight. Trees now fade out when they obstruct the player's view, improving visibility. Also includes several fixes: - Fixes tree distribution. - Adds a see-through shader. - Adds camera and occlusion scripts. --- Entities/Tree/Tree.tscn | 17 +++- Entities/Tree/scripts/tree.gd | 155 ++++++++++++++++++----------- Utilities/MapData/MapPopulation.gd | 2 +- leaves.gdshader | 4 +- project.godot | 4 + see_through.gdshader | 41 ++++++++ see_through.gdshader.uid | 1 + stages/Test3D/Test3d.tscn | 151 +++++++++++++++------------- stages/Test3D/camera_3d.gd | 69 ++++++++++++- stages/Test3D/new_environment.tres | 7 +- 10 files changed, 314 insertions(+), 137 deletions(-) create mode 100644 see_through.gdshader create mode 100644 see_through.gdshader.uid diff --git a/Entities/Tree/Tree.tscn b/Entities/Tree/Tree.tscn index a45cf43..b5924d1 100644 --- a/Entities/Tree/Tree.tscn +++ b/Entities/Tree/Tree.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=4 format=3 uid="uid://c27fogucecn0r"] +[gd_scene load_steps=5 format=3 uid="uid://c27fogucecn0r"] [ext_resource type="Script" uid="uid://lcedx3lau6v5" path="res://Entities/Tree/scripts/tree.gd" id="1_702jv"] @@ -8,6 +8,9 @@ height = 0.5 [sub_resource type="SphereShape3D" id="SphereShape3D_702jv"] +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_702jv"] +radius = 0.6 + [node name="Tree" type="Node3D"] script = ExtResource("1_702jv") @@ -20,3 +23,15 @@ shape = SubResource("CapsuleShape3D_s6kdm") [node name="CollisionShape3D" type="CollisionShape3D" parent="InteractRange"] shape = SubResource("SphereShape3D_702jv") + +[node name="VisibilityArea" type="StaticBody3D" parent="." groups=["tree_visibility"]] +collision_layer = 2 +collision_mask = 2 + +[node name="VisibilityShape" type="CollisionShape3D" parent="VisibilityArea"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.616604, 0) +shape = SubResource("CapsuleShape3D_702jv") +debug_color = Color(0.837648, 0.364145, 0.346694, 0.42) + +[node name="LastBlocked" type="Timer" parent="."] +wait_time = 0.5 diff --git a/Entities/Tree/scripts/tree.gd b/Entities/Tree/scripts/tree.gd index 3c8eb24..b6e7728 100644 --- a/Entities/Tree/scripts/tree.gd +++ b/Entities/Tree/scripts/tree.gd @@ -1,20 +1,22 @@ class_name TreeNode extends Node3D -@onready var area: Area3D = $InteractRange - var tree_data: TreeDataResource var model_instance: Node3D var mesh_instances: Array[MeshInstance3D] = [] var original_materials: Array[Material] = [] var outline_material: Material -var base_circle: MeshInstance3D -var circle_material: Material +var is_invisible: bool = false +var fade_tween: Tween + +@onready var area: Area3D = $InteractRange +@onready var last_blocked: Timer = $LastBlocked func _ready(): setup_outline_material() area.body_entered.connect(_on_player_entered) area.body_exited.connect(_on_player_exited) + last_blocked.timeout.connect(_on_fade_timer_timeout) func set_tree_data(data: TreeDataResource): tree_data = data @@ -35,16 +37,9 @@ func spawn_model(): model_instance = tree_data.model.instantiate() tree_data.apply_seasonal_colors(model_instance, Season.current) add_child(model_instance) - - - # Create base circle after model is loaded - if not base_circle: - create_base_circle() # Re-scan for mesh instances in the new model find_all_mesh_instances(model_instance) - - update_outline_materials() # Apply any additional properties from tree_data apply_tree_properties() @@ -59,7 +54,7 @@ func apply_tree_properties(): # Apply random scale based on tree properties if tree_data.max_height > 0: - var scale_variation = randf_range(0.8, 1.2) + var scale_variation = randf_range(1.5, 2) model_instance.scale *= scale_variation func setup_outline_material() -> void: @@ -68,67 +63,113 @@ func setup_outline_material() -> void: outline_material.shader = preload("res://outline.gdshader") outline_material.set_shader_parameter("color", Vector3(0.702, 0.557, 0.259)) -func update_outline_materials(): - if mesh_instances.is_empty(): - print("Warning: No MeshInstance3D found in model!") - return - - # Store original materials for the new model - original_materials.clear() - for mesh in mesh_instances: - if mesh.get_surface_override_material(0): - original_materials.append(mesh.get_surface_override_material(0)) - else: - original_materials.append(mesh.get_surface_override_material(0)) - func find_all_mesh_instances(node: Node): if node is MeshInstance3D: mesh_instances.append(node) for child in node.get_children(): find_all_mesh_instances(child) -func create_base_circle(): - base_circle = MeshInstance3D.new() - add_child(base_circle) +func fade_out_tree_simple(duration: float = 0.25): + # Reset the timer + last_blocked.stop() + last_blocked.start() - # Create a flat cylinder for the circle - var cylinder = CylinderMesh.new() - cylinder.top_radius = 0.4 # Adjust size as needed - cylinder.bottom_radius = 0.4 - cylinder.height = 1 # Very thin to make it look like a flat circle - cylinder.rings = 1 - cylinder.radial_segments = 9 # More segments = smoother circle - base_circle.mesh = cylinder - - # Create transparent material with outline - circle_material = StandardMaterial3D.new() - circle_material.flags_transparent = true - circle_material.albedo_color = Color(1.0, 0.843, 0.0, 0.0) # Fully transparent gold - - # Add rim lighting effect for outline appearance - circle_material.rim_enabled = true - circle_material.rim = 1.0 - circle_material.rim_tint = 1.0 - circle_material.rim_color = Color(1.0, 0.843, 0.0) # Gold rim - base_circle.material_override = circle_material + if is_invisible: + return - base_circle.position.y = 1 # Slightly above ground to avoid z-fighting + is_invisible = true - # Start hidden - base_circle.visible = true + # Kill any existing fade tween + if fade_tween: + fade_tween.kill() + + for mesh_instance in mesh_instances: + fade_mesh_materials(mesh_instance, 1.0, 0.1, duration) +# This gets called when the timer times out +func _on_fade_timer_timeout(): + fade_in_tree_immediate() + +func fade_in_tree_immediate(duration: float = 0.25): + if not is_invisible: + return + + # Kill any existing fade tween + if fade_tween: + fade_tween.kill() + + for mesh_instance in mesh_instances: + fade_mesh_materials(mesh_instance, 0.1, 1.0, duration) + + is_invisible = false + +func fade_mesh_materials(mesh_instance: MeshInstance3D, from_alpha: float, to_alpha: float, duration: float): + if not mesh_instance.mesh: + return + + var surface_count = mesh_instance.mesh.get_surface_count() + + for surface_id in range(surface_count): + var material = mesh_instance.get_surface_override_material(surface_id) + + # Always ensure we have a unique material instance + if not material: + # No override material - duplicate from base material + var base_material = mesh_instance.mesh.surface_get_material(surface_id) + if base_material: + material = base_material.duplicate() + mesh_instance.set_surface_override_material(surface_id, material) + else: + # Override material exists - duplicate it to ensure uniqueness + material = material.duplicate() + mesh_instance.set_surface_override_material(surface_id, material) + + # Only work with StandardMaterial3D + if material and material is StandardMaterial3D: + var std_mat = material as StandardMaterial3D + + # Set transparency mode based on target alpha + if to_alpha < 1.0: + std_mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA + + # Force shadow casting + mesh_instance.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_ON + + # Set initial alpha + std_mat.albedo_color.a = from_alpha + + # Create and store the tween + fade_tween = create_tween() + fade_tween.tween_method( + func(alpha: float): + std_mat.albedo_color.a = alpha, + from_alpha, to_alpha, duration + ) + + # When fading to full opacity, reset transparency mode + if to_alpha >= 1.0: + fade_tween.tween_callback( + func(): std_mat.transparency = BaseMaterial3D.TRANSPARENCY_DISABLED + ) + +func toggle_tree_visibility(duration: float = 1.0): + if is_invisible: + fade_in_tree_immediate(duration) + else: + fade_out_tree_simple(duration) func _on_player_entered(body: Node3D): if body.is_in_group("player"): - base_circle.visible = true # Apply outline to all mesh instances - for mesh in mesh_instances: - mesh.material_overlay = outline_material + if not is_invisible: + for mesh in mesh_instances: + mesh.material_overlay = outline_material func _on_player_exited(body: Node3D): if body.is_in_group("player"): Log.pr('Out of range...') - base_circle.visible = false # Remove outline from all mesh instances - for mesh in mesh_instances: - mesh.material_overlay = null + if not is_invisible: + # Reset the material overlay to null + for mesh in mesh_instances: + mesh.material_overlay = null diff --git a/Utilities/MapData/MapPopulation.gd b/Utilities/MapData/MapPopulation.gd index 6974a04..e8caf6c 100644 --- a/Utilities/MapData/MapPopulation.gd +++ b/Utilities/MapData/MapPopulation.gd @@ -44,7 +44,7 @@ static func calculate_tree_distribution(tree_preferences: Dictionary, density: f return distribution # Calculate total number of trees for this cell - var total_trees = int((density / 2) * 10) + randi_range(1, 3) + var total_trees = int((density / 5) * 10) + randi_range(1, 2) #var total_trees = int((density - 0.6) * 25) + randi_range(3, 8) # Normalize the chances to get proportions diff --git a/leaves.gdshader b/leaves.gdshader index 4ba6f4e..34b99f4 100644 --- a/leaves.gdshader +++ b/leaves.gdshader @@ -14,9 +14,9 @@ void fragment() { // Use world Y position instead of UV float gradient_factor = (world_position.y + gradient_offset) / gradient_height; gradient_factor = clamp(gradient_factor, 0.0, 1.0); - + vec3 final_color = mix(base_color.rgb, variation_color.rgb, gradient_factor); - + ALBEDO = final_color; ROUGHNESS = 0.8; METALLIC = 0.0; diff --git a/project.godot b/project.godot index fe1e629..482f2b3 100644 --- a/project.godot +++ b/project.godot @@ -64,6 +64,10 @@ jump={ ] } +[layer_names] + +3d_physics/layer_4="TreeVisibility" + [network] limits/debugger/max_chars_per_second=1000000 diff --git a/see_through.gdshader b/see_through.gdshader new file mode 100644 index 0000000..df0631f --- /dev/null +++ b/see_through.gdshader @@ -0,0 +1,41 @@ +shader_type spatial; + +// Uniforms that can be controlled from GDScript +uniform float model_height : hint_range(0.1, 100.0) = 10.0; +uniform float transition_width : hint_range(0.01, 0.5) = 0.1; +uniform vec4 base_color : source_color = vec4(1.0, 1.0, 1.0, 1.0); +uniform float effect_strength : hint_range(0.0, 1.0) = 1.0; +uniform sampler2D main_texture : source_color; +uniform float metallic : hint_range(0.0, 1.0) = 0.0; +uniform float roughness : hint_range(0.0, 1.0) = 0.5; + +varying vec3 world_position; + +void vertex() { + world_position = VERTEX; +} + +void fragment() { + // Get the base texture color + vec4 tex_color = texture(main_texture, UV); + + // Calculate normalized Y position (0.0 at bottom, 1.0 at top) + // This uses the local vertex position - adjust based on your model's bounds + float normalized_y = (world_position.y + model_height * 0.5) / model_height; + + // Define fade boundaries - top 80% invisible, bottom 20% visible + float fade_start = 0.2; // Start fading at 20% from bottom + float fade_end = fade_start - transition_width; + + // Calculate position-based alpha + float position_alpha = smoothstep(fade_end, fade_start, normalized_y); + + // Blend between full visibility and position-based alpha based on effect strength + float final_alpha = mix(1.0, position_alpha, effect_strength); + + // Set material properties + ALBEDO = base_color.rgb * tex_color.rgb; + ALPHA = base_color.a * tex_color.a * final_alpha; + METALLIC = metallic; + ROUGHNESS = roughness; +} \ No newline at end of file diff --git a/see_through.gdshader.uid b/see_through.gdshader.uid new file mode 100644 index 0000000..40c1172 --- /dev/null +++ b/see_through.gdshader.uid @@ -0,0 +1 @@ +uid://djv8r207ldqn1 diff --git a/stages/Test3D/Test3d.tscn b/stages/Test3D/Test3d.tscn index 7ee8fd9..25914db 100644 --- a/stages/Test3D/Test3d.tscn +++ b/stages/Test3D/Test3d.tscn @@ -1,10 +1,12 @@ -[gd_scene load_steps=53 format=4 uid="uid://bwsugg4p50fjr"] +[gd_scene load_steps=55 format=4 uid="uid://bwsugg4p50fjr"] [ext_resource type="Environment" uid="uid://cm77bbr0io118" path="res://Stages/Test3D/new_environment.tres" id="1_8ph61"] [ext_resource type="Script" uid="uid://bwed2dwogfmxv" path="res://Entities/Player/scripts/player.gd" id="1_d602n"] [ext_resource type="AnimationLibrary" uid="uid://bwnn7vpd0dqds" path="res://Common/animations/basic-movement.res" id="1_tfa5t"] [ext_resource type="Script" uid="uid://bbjv6a7yg7m02" path="res://Stages/Test3D/camera_pivot.gd" id="2_sdmks"] [ext_resource type="Shader" uid="uid://bsemnmdracd4m" path="res://Common/shaders/outline.gdshader" id="4_feu7y"] +[ext_resource type="Script" uid="uid://cjbk6jnxla4mn" path="res://Stages/Test3D/camera_3d.gd" id="5_fm6lr"] +[ext_resource type="PackedScene" uid="uid://isogcpkb8su4" path="res://Entities/Tree/assets/temp/tent_detailedOpen.glb" id="9_4jb6r"] [ext_resource type="Script" uid="uid://bjco8musjqog4" path="res://Stages/Test3D/particles.gd" id="9_oiyue"] [ext_resource type="PackedScene" uid="uid://cdbnr0jg2icaj" path="res://Entities/Tree/assets/temp/campfire_bricks.glb" id="13_qasnx"] [ext_resource type="PackedScene" uid="uid://c4ovjmemnepdy" path="res://Entities/Tree/assets/temp/campfire_logs.glb" id="14_2xm50"] @@ -372,42 +374,6 @@ size = Vector2(2, 2) [sub_resource type="BoxShape3D" id="BoxShape3D_tfa5t"] size = Vector3(60, 0, 20) -[sub_resource type="Curve" id="Curve_5r2bu"] -_data = [Vector2(0.003125, 0.0237797), 0.0, 0.0, 0, 0, Vector2(0.21875, 0.877972), 0.0, 0.0, 0, 0, Vector2(0.41875, 0.194618), 0.0, 0.0, 0, 0, Vector2(0.478125, 0.576971), -7.27116, -7.27116, 0, 0, Vector2(0.621875, 0.227159), 0.0, 0.0, 0, 0, Vector2(0.7625, 0.365457), 0.0, 0.0, 0, 0, Vector2(1, 0.04005), 0.0, 0.0, 0, 0] -point_count = 7 - -[sub_resource type="CurveTexture" id="CurveTexture_23r73"] -curve = SubResource("Curve_5r2bu") - -[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_p5fn2"] -emission_shape = 6 -emission_ring_axis = Vector3(0, 1, 0) -emission_ring_height = 1.0 -emission_ring_radius = 5.0 -emission_ring_inner_radius = 0.0 -emission_ring_cone_angle = 90.0 -direction = Vector3(0.2, -1, 0) -spread = 5.0 -initial_velocity_max = 10.0 -scale_min = 0.1 -alpha_curve = SubResource("CurveTexture_23r73") -collision_mode = 2 - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_p5fn2"] -transparency = 1 -cull_mode = 2 -shading_mode = 0 -vertex_color_use_as_albedo = true -albedo_color = Color(1, 1, 1, 0.807843) -albedo_texture = ExtResource("23_23r73") -use_particle_trails = true - -[sub_resource type="RibbonTrailMesh" id="RibbonTrailMesh_5r2bu"] -material = SubResource("StandardMaterial3D_p5fn2") -size = 0.025 -sections = 2 -section_segments = 1 - [sub_resource type="Curve" id="Curve_ukp6m"] _data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.515625, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] point_count = 3 @@ -450,6 +416,42 @@ material = SubResource("StandardMaterial3D_hvb1l") size = Vector2(0.2, 0.2) orientation = 0 +[sub_resource type="Curve" id="Curve_5r2bu"] +_data = [Vector2(0.003125, 0.0237797), 0.0, 0.0, 0, 0, Vector2(0.21875, 0.877972), 0.0, 0.0, 0, 0, Vector2(0.41875, 0.194618), 0.0, 0.0, 0, 0, Vector2(0.478125, 0.576971), -7.27116, -7.27116, 0, 0, Vector2(0.621875, 0.227159), 0.0, 0.0, 0, 0, Vector2(0.7625, 0.365457), 0.0, 0.0, 0, 0, Vector2(1, 0.04005), 0.0, 0.0, 0, 0] +point_count = 7 + +[sub_resource type="CurveTexture" id="CurveTexture_23r73"] +curve = SubResource("Curve_5r2bu") + +[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_p5fn2"] +emission_shape = 6 +emission_ring_axis = Vector3(0, 1, 0) +emission_ring_height = 1.0 +emission_ring_radius = 5.0 +emission_ring_inner_radius = 0.0 +emission_ring_cone_angle = 90.0 +direction = Vector3(0.2, -1, 0) +spread = 5.0 +initial_velocity_max = 10.0 +scale_min = 0.1 +alpha_curve = SubResource("CurveTexture_23r73") +collision_mode = 2 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_p5fn2"] +transparency = 1 +cull_mode = 2 +shading_mode = 0 +vertex_color_use_as_albedo = true +albedo_color = Color(1, 1, 1, 0.807843) +albedo_texture = ExtResource("23_23r73") +use_particle_trails = true + +[sub_resource type="RibbonTrailMesh" id="RibbonTrailMesh_5r2bu"] +material = SubResource("StandardMaterial3D_p5fn2") +size = 0.025 +sections = 2 +section_segments = 1 + [node name="Test3d" type="Node3D"] [node name="WorldEnvironment" type="WorldEnvironment" parent="."] @@ -748,9 +750,10 @@ script = ExtResource("2_sdmks") transform = Transform3D(1, 0, 0, 0, 1, 1.78814e-07, 0, -3.27826e-07, 1, 0, 0, 7) projection = 1 current = true -size = 3.0 +size = 4.0 near = 0.001 far = 100.0 +script = ExtResource("5_fm6lr") [node name="PostProcessing" type="MeshInstance3D" parent="SubViewportContainer/SubViewport/Player/CameraPivot/Camera3D"] unique_name_in_owner = true @@ -759,6 +762,9 @@ visible = false extra_cull_margin = 16384.0 mesh = SubResource("QuadMesh_tfa5t") +[node name="RayCast3D" type="RayCast3D" parent="SubViewportContainer/SubViewport/Player/CameraPivot/Camera3D"] +collision_mask = 3 + [node name="Environment" type="Node3D" parent="SubViewportContainer/SubViewport"] [node name="Ground" type="StaticBody3D" parent="SubViewportContainer/SubViewport/Environment"] @@ -781,17 +787,49 @@ unique_name_in_owner = true [node name="Objects" type="Node3D" parent="SubViewportContainer/SubViewport/Camp"] -[node name="tent-canvas2" parent="SubViewportContainer/SubViewport/Camp/Objects" instance=ExtResource("23_5r2bu")] -transform = Transform3D(0.964438, 0, -0.264311, 0, 1, 0, 0.264311, 0, 0.964438, -1.40178, 0, -1.67128) +[node name="Camp" type="Node3D" parent="SubViewportContainer/SubViewport/Camp/Objects"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.718493, 0, -0.353187) -[node name="campfire_bricks2" parent="SubViewportContainer/SubViewport/Camp/Objects" instance=ExtResource("13_qasnx")] +[node name="tent_detailedOpen2" parent="SubViewportContainer/SubViewport/Camp/Objects/Camp" instance=ExtResource("9_4jb6r")] +transform = Transform3D(-0.993544, 0, 0.113446, 0, 1, 0, -0.113446, 0, -0.993544, -0.933611, 0.05, -1.63291) + +[node name="tent-canvas2" parent="SubViewportContainer/SubViewport/Camp/Objects/Camp" instance=ExtResource("23_5r2bu")] +transform = Transform3D(0.964438, 0, -0.264311, 0, 1, 0, 0.264311, 0, 0.964438, -1.40178, 0, -1.67128) +visible = false + +[node name="Campfire" parent="SubViewportContainer/SubViewport/Camp/Objects/Camp" instance=ExtResource("13_qasnx")] transform = Transform3D(0.7, 0, 0, 0, 0.7, 0, 0, 0, 0.7, -0.93138, 0.05, -0.326702) -[node name="campfire_logs2" parent="SubViewportContainer/SubViewport/Camp/Objects/campfire_bricks2" instance=ExtResource("14_2xm50")] +[node name="campfire_logs2" parent="SubViewportContainer/SubViewport/Camp/Objects/Camp/Campfire" instance=ExtResource("14_2xm50")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0053246, 0, 0.0117908) -[node name="log2" parent="SubViewportContainer/SubViewport/Camp/Objects" instance=ExtResource("15_e0hgm")] -transform = Transform3D(0.440003, 0, 0.237482, 0, 0.5, 0, -0.237482, 0, 0.440003, -0.565749, 0.0532002, -0.598678) +[node name="Fire" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/Camp/Objects/Camp/Campfire"] +transform = Transform3D(1.42857, 0, 0, 0, 1.42857, 0, 0, 0, 1.42857, 0, 0, 0) +amount = 50 +lifetime = 0.4 +speed_scale = 0.4 +process_material = SubResource("ParticleProcessMaterial_xvexm") +draw_pass_1 = SubResource("QuadMesh_hvb1l") + +[node name="OmniLight3D" type="OmniLight3D" parent="SubViewportContainer/SubViewport/Camp/Objects/Camp/Campfire/Fire"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.000509977, 0.121094, -0.00151992) +light_color = Color(0.89, 0.461613, 0.2136, 1) +light_energy = 0.923321 +light_indirect_energy = 1.084 +light_volumetric_fog_energy = 3.764 +light_size = 0.105 +shadow_enabled = true +distance_fade_enabled = true +distance_fade_begin = 386.01 +distance_fade_shadow = 45.9 +distance_fade_length = 28.05 +script = ExtResource("22_ukp6m") + +[node name="log2" parent="SubViewportContainer/SubViewport/Camp/Objects/Camp" instance=ExtResource("15_e0hgm")] +transform = Transform3D(0.440003, 0, 0.237482, 0, 0.5, 0, -0.237482, 0, 0.440003, -0.566, 0.006, -0.599) + +[node name="bed_floor2" parent="SubViewportContainer/SubViewport/Camp/Objects/Camp" instance=ExtResource("15_pbfwi")] +transform = Transform3D(0.72094, 0, -0.346764, 0, 0.8, 0, 0.346764, 0, 0.72094, -1.4942, 0.00999988, -0.784986) [node name="statue_column2" parent="SubViewportContainer/SubViewport/Camp/Objects" instance=ExtResource("16_ynokf")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.654, 0, -2.707) @@ -805,9 +843,6 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.727, 0, 0.611) [node name="statue_columnDamaged2" parent="SubViewportContainer/SubViewport/Camp/Objects" instance=ExtResource("17_pbfwi")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.609224, 0, 0.72) -[node name="bed_floor2" parent="SubViewportContainer/SubViewport/Camp/Objects" instance=ExtResource("15_pbfwi")] -transform = Transform3D(0.72094, 0, -0.346764, 0, 0.8, 0, 0.346764, 0, 0.72094, -1.54675, 0.0359214, -1.37165) - [node name="VFX" type="Node3D" parent="SubViewportContainer/SubViewport/Camp"] [node name="Rain" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/Camp/VFX"] @@ -821,28 +856,6 @@ trail_lifetime = 0.1 process_material = SubResource("ParticleProcessMaterial_p5fn2") draw_pass_1 = SubResource("RibbonTrailMesh_5r2bu") -[node name="Fire" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/Camp/VFX"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.923367, 0.0346675, -0.309572) -amount = 50 -lifetime = 0.4 -speed_scale = 0.4 -process_material = SubResource("ParticleProcessMaterial_xvexm") -draw_pass_1 = SubResource("QuadMesh_hvb1l") - -[node name="OmniLight3D" type="OmniLight3D" parent="SubViewportContainer/SubViewport/Camp/VFX/Fire"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.000509977, 0.121094, -0.00151992) -light_color = Color(0.89, 0.461613, 0.2136, 1) -light_energy = 0.716329 -light_indirect_energy = 1.084 -light_volumetric_fog_energy = 3.764 -light_size = 0.105 -shadow_enabled = true -distance_fade_enabled = true -distance_fade_begin = 386.01 -distance_fade_shadow = 45.9 -distance_fade_length = 28.05 -script = ExtResource("22_ukp6m") - [node name="UISubViewportContainer" type="SubViewportContainer" parent="."] anchors_preset = 15 anchor_right = 1.0 diff --git a/stages/Test3D/camera_3d.gd b/stages/Test3D/camera_3d.gd index 2f5ed09..30cd5fe 100644 --- a/stages/Test3D/camera_3d.gd +++ b/stages/Test3D/camera_3d.gd @@ -1,6 +1,69 @@ extends Camera3D +@export var player: Node3D # Assign your player node in the editor -var speed_factor = 3 +func _ready(): + player = %Player -func _physics_process(delta): - position = lerp(position, %Player.position, speed_factor * delta) \ No newline at end of file +func _process(delta): + if player: + check_line_of_sight_to_player() + +func check_line_of_sight_to_player(): + var start_pos = global_position + var end_pos = player.global_position + var direction = (end_pos - start_pos).normalized() + var max_distance = start_pos.distance_to(end_pos) + + var space_state = get_world_3d().direct_space_state + var current_distance = 0.0 + var hit_trees: Array[Node] = [] + + # Keep casting rays until we reach the player + while current_distance < max_distance - 0.1: + var current_start = start_pos + direction * current_distance + var current_end = end_pos + + # Create ray query + var query = PhysicsRayQueryParameters3D.create(current_start, current_end) + var result = space_state.intersect_ray(query) + + if result.is_empty(): + # No obstacles, clear line of sight + break + + var hit_object = result.collider + var hit_point = result.position + var distance_to_hit = current_start.distance_to(hit_point) + + # If we hit a tree, add it to the list + if hit_object.is_in_group("tree_visibility"): + if hit_object not in hit_trees: + hit_trees.append(hit_object) + # Only fade if player is behind the tree + if is_player_behind_tree(hit_object): + tree_is_blocking_player(hit_object) + + # Move past the hit point for next iteration + current_distance += distance_to_hit + 0.1 + + # Safety check to prevent infinite loops + if distance_to_hit < 0.01: + current_distance += 0.5 + +func is_player_behind_tree(tree_object: Node) -> bool: + var camera_pos = global_position + var player_pos = player.global_position + var tree_pos = tree_object.global_position + + # Calculate distances from camera + var camera_to_tree_distance = camera_pos.distance_to(tree_pos) + var camera_to_player_distance = camera_pos.distance_to(player_pos) + + # Tree should be faded if it's closer to camera than player + # (tree is between camera and player) + var buffer = 0.2 # Small buffer to avoid flickering + return camera_to_tree_distance < (camera_to_player_distance - buffer) + +func tree_is_blocking_player(tree_object): + # Fade out the blocking tree + tree_object.get_parent().fade_out_tree_simple() diff --git a/stages/Test3D/new_environment.tres b/stages/Test3D/new_environment.tres index 0cfe14c..bd40820 100644 --- a/stages/Test3D/new_environment.tres +++ b/stages/Test3D/new_environment.tres @@ -10,11 +10,10 @@ sky_material = SubResource("ProceduralSkyMaterial_lg8b7") [resource] background_mode = 2 -background_color = Color(0.752941, 0.776471, 0.827451, 1) +background_color = Color(1, 1, 0.603922, 1) sky = SubResource("Sky_7bk1c") -ambient_light_source = 2 -ambient_light_color = Color(0.662745, 0.694118, 0.772549, 1) -ambient_light_energy = 0.5 +ambient_light_source = 3 +ambient_light_color = Color(0.800491, 0.800491, 0.800491, 1) reflected_light_source = 2 tonemap_mode = 2 ssil_enabled = true