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.
This commit is contained in:
parent
a1efaf6294
commit
f98773237e
10 changed files with 314 additions and 137 deletions
|
|
@ -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"]
|
[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="SphereShape3D" id="SphereShape3D_702jv"]
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_702jv"]
|
||||||
|
radius = 0.6
|
||||||
|
|
||||||
[node name="Tree" type="Node3D"]
|
[node name="Tree" type="Node3D"]
|
||||||
script = ExtResource("1_702jv")
|
script = ExtResource("1_702jv")
|
||||||
|
|
||||||
|
|
@ -20,3 +23,15 @@ shape = SubResource("CapsuleShape3D_s6kdm")
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="InteractRange"]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="InteractRange"]
|
||||||
shape = SubResource("SphereShape3D_702jv")
|
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
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,22 @@
|
||||||
class_name TreeNode
|
class_name TreeNode
|
||||||
extends Node3D
|
extends Node3D
|
||||||
|
|
||||||
@onready var area: Area3D = $InteractRange
|
|
||||||
|
|
||||||
var tree_data: TreeDataResource
|
var tree_data: TreeDataResource
|
||||||
var model_instance: Node3D
|
var model_instance: Node3D
|
||||||
var mesh_instances: Array[MeshInstance3D] = []
|
var mesh_instances: Array[MeshInstance3D] = []
|
||||||
var original_materials: Array[Material] = []
|
var original_materials: Array[Material] = []
|
||||||
var outline_material: Material
|
var outline_material: Material
|
||||||
var base_circle: MeshInstance3D
|
var is_invisible: bool = false
|
||||||
var circle_material: Material
|
var fade_tween: Tween
|
||||||
|
|
||||||
|
@onready var area: Area3D = $InteractRange
|
||||||
|
@onready var last_blocked: Timer = $LastBlocked
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
setup_outline_material()
|
setup_outline_material()
|
||||||
area.body_entered.connect(_on_player_entered)
|
area.body_entered.connect(_on_player_entered)
|
||||||
area.body_exited.connect(_on_player_exited)
|
area.body_exited.connect(_on_player_exited)
|
||||||
|
last_blocked.timeout.connect(_on_fade_timer_timeout)
|
||||||
|
|
||||||
func set_tree_data(data: TreeDataResource):
|
func set_tree_data(data: TreeDataResource):
|
||||||
tree_data = data
|
tree_data = data
|
||||||
|
|
@ -36,16 +38,9 @@ func spawn_model():
|
||||||
tree_data.apply_seasonal_colors(model_instance, Season.current)
|
tree_data.apply_seasonal_colors(model_instance, Season.current)
|
||||||
add_child(model_instance)
|
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
|
# Re-scan for mesh instances in the new model
|
||||||
find_all_mesh_instances(model_instance)
|
find_all_mesh_instances(model_instance)
|
||||||
|
|
||||||
update_outline_materials()
|
|
||||||
|
|
||||||
# Apply any additional properties from tree_data
|
# Apply any additional properties from tree_data
|
||||||
apply_tree_properties()
|
apply_tree_properties()
|
||||||
|
|
||||||
|
|
@ -59,7 +54,7 @@ func apply_tree_properties():
|
||||||
|
|
||||||
# Apply random scale based on tree properties
|
# Apply random scale based on tree properties
|
||||||
if tree_data.max_height > 0:
|
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
|
model_instance.scale *= scale_variation
|
||||||
|
|
||||||
func setup_outline_material() -> void:
|
func setup_outline_material() -> void:
|
||||||
|
|
@ -68,67 +63,113 @@ func setup_outline_material() -> void:
|
||||||
outline_material.shader = preload("res://outline.gdshader")
|
outline_material.shader = preload("res://outline.gdshader")
|
||||||
outline_material.set_shader_parameter("color", Vector3(0.702, 0.557, 0.259))
|
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):
|
func find_all_mesh_instances(node: Node):
|
||||||
if node is MeshInstance3D:
|
if node is MeshInstance3D:
|
||||||
mesh_instances.append(node)
|
mesh_instances.append(node)
|
||||||
for child in node.get_children():
|
for child in node.get_children():
|
||||||
find_all_mesh_instances(child)
|
find_all_mesh_instances(child)
|
||||||
|
|
||||||
func create_base_circle():
|
func fade_out_tree_simple(duration: float = 0.25):
|
||||||
base_circle = MeshInstance3D.new()
|
# Reset the timer
|
||||||
add_child(base_circle)
|
last_blocked.stop()
|
||||||
|
last_blocked.start()
|
||||||
|
|
||||||
# Create a flat cylinder for the circle
|
if is_invisible:
|
||||||
var cylinder = CylinderMesh.new()
|
return
|
||||||
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
|
is_invisible = true
|
||||||
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
|
# Kill any existing fade tween
|
||||||
circle_material.rim_enabled = true
|
if fade_tween:
|
||||||
circle_material.rim = 1.0
|
fade_tween.kill()
|
||||||
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
|
|
||||||
|
|
||||||
base_circle.position.y = 1 # Slightly above ground to avoid z-fighting
|
for mesh_instance in mesh_instances:
|
||||||
|
fade_mesh_materials(mesh_instance, 1.0, 0.1, duration)
|
||||||
|
|
||||||
# Start hidden
|
# This gets called when the timer times out
|
||||||
base_circle.visible = true
|
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):
|
func _on_player_entered(body: Node3D):
|
||||||
if body.is_in_group("player"):
|
if body.is_in_group("player"):
|
||||||
base_circle.visible = true
|
|
||||||
# Apply outline to all mesh instances
|
# Apply outline to all mesh instances
|
||||||
|
if not is_invisible:
|
||||||
for mesh in mesh_instances:
|
for mesh in mesh_instances:
|
||||||
mesh.material_overlay = outline_material
|
mesh.material_overlay = outline_material
|
||||||
|
|
||||||
func _on_player_exited(body: Node3D):
|
func _on_player_exited(body: Node3D):
|
||||||
if body.is_in_group("player"):
|
if body.is_in_group("player"):
|
||||||
Log.pr('Out of range...')
|
Log.pr('Out of range...')
|
||||||
base_circle.visible = false
|
|
||||||
# Remove outline from all mesh instances
|
# Remove outline from all mesh instances
|
||||||
|
if not is_invisible:
|
||||||
|
# Reset the material overlay to null
|
||||||
for mesh in mesh_instances:
|
for mesh in mesh_instances:
|
||||||
mesh.material_overlay = null
|
mesh.material_overlay = null
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ static func calculate_tree_distribution(tree_preferences: Dictionary, density: f
|
||||||
return distribution
|
return distribution
|
||||||
|
|
||||||
# Calculate total number of trees for this cell
|
# 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)
|
#var total_trees = int((density - 0.6) * 25) + randi_range(3, 8)
|
||||||
|
|
||||||
# Normalize the chances to get proportions
|
# Normalize the chances to get proportions
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,10 @@ jump={
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[layer_names]
|
||||||
|
|
||||||
|
3d_physics/layer_4="TreeVisibility"
|
||||||
|
|
||||||
[network]
|
[network]
|
||||||
|
|
||||||
limits/debugger/max_chars_per_second=1000000
|
limits/debugger/max_chars_per_second=1000000
|
||||||
|
|
|
||||||
41
see_through.gdshader
Normal file
41
see_through.gdshader
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
1
see_through.gdshader.uid
Normal file
1
see_through.gdshader.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://djv8r207ldqn1
|
||||||
|
|
@ -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="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="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="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="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="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="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://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"]
|
[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"]
|
[sub_resource type="BoxShape3D" id="BoxShape3D_tfa5t"]
|
||||||
size = Vector3(60, 0, 20)
|
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"]
|
[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]
|
_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
|
point_count = 3
|
||||||
|
|
@ -450,6 +416,42 @@ material = SubResource("StandardMaterial3D_hvb1l")
|
||||||
size = Vector2(0.2, 0.2)
|
size = Vector2(0.2, 0.2)
|
||||||
orientation = 0
|
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="Test3d" type="Node3D"]
|
||||||
|
|
||||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
[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)
|
transform = Transform3D(1, 0, 0, 0, 1, 1.78814e-07, 0, -3.27826e-07, 1, 0, 0, 7)
|
||||||
projection = 1
|
projection = 1
|
||||||
current = true
|
current = true
|
||||||
size = 3.0
|
size = 4.0
|
||||||
near = 0.001
|
near = 0.001
|
||||||
far = 100.0
|
far = 100.0
|
||||||
|
script = ExtResource("5_fm6lr")
|
||||||
|
|
||||||
[node name="PostProcessing" type="MeshInstance3D" parent="SubViewportContainer/SubViewport/Player/CameraPivot/Camera3D"]
|
[node name="PostProcessing" type="MeshInstance3D" parent="SubViewportContainer/SubViewport/Player/CameraPivot/Camera3D"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|
@ -759,6 +762,9 @@ visible = false
|
||||||
extra_cull_margin = 16384.0
|
extra_cull_margin = 16384.0
|
||||||
mesh = SubResource("QuadMesh_tfa5t")
|
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="Environment" type="Node3D" parent="SubViewportContainer/SubViewport"]
|
||||||
|
|
||||||
[node name="Ground" type="StaticBody3D" parent="SubViewportContainer/SubViewport/Environment"]
|
[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="Objects" type="Node3D" parent="SubViewportContainer/SubViewport/Camp"]
|
||||||
|
|
||||||
[node name="tent-canvas2" parent="SubViewportContainer/SubViewport/Camp/Objects" instance=ExtResource("23_5r2bu")]
|
[node name="Camp" type="Node3D" parent="SubViewportContainer/SubViewport/Camp/Objects"]
|
||||||
transform = Transform3D(0.964438, 0, -0.264311, 0, 1, 0, 0.264311, 0, 0.964438, -1.40178, 0, -1.67128)
|
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)
|
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)
|
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")]
|
[node name="Fire" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/Camp/Objects/Camp/Campfire"]
|
||||||
transform = Transform3D(0.440003, 0, 0.237482, 0, 0.5, 0, -0.237482, 0, 0.440003, -0.565749, 0.0532002, -0.598678)
|
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")]
|
[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)
|
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")]
|
[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)
|
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="VFX" type="Node3D" parent="SubViewportContainer/SubViewport/Camp"]
|
||||||
|
|
||||||
[node name="Rain" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/Camp/VFX"]
|
[node name="Rain" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/Camp/VFX"]
|
||||||
|
|
@ -821,28 +856,6 @@ trail_lifetime = 0.1
|
||||||
process_material = SubResource("ParticleProcessMaterial_p5fn2")
|
process_material = SubResource("ParticleProcessMaterial_p5fn2")
|
||||||
draw_pass_1 = SubResource("RibbonTrailMesh_5r2bu")
|
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="."]
|
[node name="UISubViewportContainer" type="SubViewportContainer" parent="."]
|
||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,69 @@
|
||||||
extends Camera3D
|
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):
|
func _process(delta):
|
||||||
position = lerp(position, %Player.position, speed_factor * 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()
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,10 @@ sky_material = SubResource("ProceduralSkyMaterial_lg8b7")
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
background_mode = 2
|
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")
|
sky = SubResource("Sky_7bk1c")
|
||||||
ambient_light_source = 2
|
ambient_light_source = 3
|
||||||
ambient_light_color = Color(0.662745, 0.694118, 0.772549, 1)
|
ambient_light_color = Color(0.800491, 0.800491, 0.800491, 1)
|
||||||
ambient_light_energy = 0.5
|
|
||||||
reflected_light_source = 2
|
reflected_light_source = 2
|
||||||
tonemap_mode = 2
|
tonemap_mode = 2
|
||||||
ssil_enabled = true
|
ssil_enabled = true
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue