diff --git a/Entities/GroundTile/GroundTile.gdshader b/Entities/GroundTile/GroundTile.gdshader new file mode 100644 index 0000000..28b7061 --- /dev/null +++ b/Entities/GroundTile/GroundTile.gdshader @@ -0,0 +1,16 @@ +shader_type spatial; + +uniform sampler2D noise_texture : filter_linear_mipmap; +uniform sampler2D gradient_texture : filter_linear; +uniform float noise_scale : hint_range(0.1, 10.0) = 1.0; +uniform float roughness_value : hint_range(0.0, 1.0) = 0.8; + +void fragment() { + vec2 noise_uv = UV * noise_scale; + float noise_val = texture(noise_texture, noise_uv).r; + + vec4 earth_color = texture(gradient_texture, vec2(noise_val, 0.0)); + + ALBEDO = earth_color.rgb; + ROUGHNESS = roughness_value; +} \ No newline at end of file diff --git a/Entities/GroundTile/GroundTile.gdshader.uid b/Entities/GroundTile/GroundTile.gdshader.uid new file mode 100644 index 0000000..c9cb91f --- /dev/null +++ b/Entities/GroundTile/GroundTile.gdshader.uid @@ -0,0 +1 @@ +uid://cuew4u0k6md1v diff --git a/Entities/GroundTile/GroundTile.tscn b/Entities/GroundTile/GroundTile.tscn index c2ab9ef..85f90f6 100644 --- a/Entities/GroundTile/GroundTile.tscn +++ b/Entities/GroundTile/GroundTile.tscn @@ -1,43 +1,84 @@ -[gd_scene load_steps=7 format=3 uid="uid://bwcevwwphdvq"] +[gd_scene load_steps=18 format=3 uid="uid://bwcevwwphdvq"] [ext_resource type="Script" uid="uid://bq7hia2dit80y" path="res://Entities/GroundTile/ground_tile.gd" id="1_uwxqs"] [ext_resource type="PackedScene" uid="uid://ckesk3bs6g7tt" path="res://Stages/Test3D/assets/fish.glb" id="2_h4g11"] +[ext_resource type="ArrayMesh" uid="uid://duj6747nq4qsk" path="res://Stages/Test3D/assets/stylizedGrassMeshes/grass.res" id="3_8mhad"] +[ext_resource type="Script" uid="uid://cacp8ncwuofuj" path="res://Entities/GroundTile/scripts/grass.gd" id="3_224hx"] +[ext_resource type="Material" uid="uid://b1miqvl8lus75" path="res://Stages/Test3D/GrassMaterialOverride.tres" id="3_f37ob"] +[ext_resource type="Script" uid="uid://btju6b83mvgvk" path="res://Entities/GroundTile/scripts/grass_multimesh.gd" id="4_3wpcb"] +[ext_resource type="PackedScene" uid="uid://dgvycnw8hpebx" path="res://Stages/Test3D/assets/tree-tall.glb" id="6_7lc7k"] +[ext_resource type="Script" uid="uid://cqko4m7cbxsfb" path="res://Entities/GroundTile/scripts/trees.gd" id="7_7lc7k"] +[ext_resource type="PackedScene" uid="uid://cccqxa0y0ksju" path="res://Stages/Test3D/assets/tree-trunk.glb" id="7_jysav"] +[ext_resource type="PackedScene" uid="uid://cwfp2cf8no8fi" path="res://Stages/Test3D/assets/tree.glb" id="8_q0r4p"] +[ext_resource type="PackedScene" uid="uid://bwdibgbi3ycqn" path="res://Stages/Test3D/assets/tree-autumn-tall.glb" id="12_4hjaq"] -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_oqd8f"] -albedo_color = Color(0.171, 0.57, 0.24415, 1) +[sub_resource type="ViewportTexture" id="ViewportTexture_h4g11"] +viewport_path = NodePath("DebugText/DebugTextViewport") + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_f37ob"] +albedo_color = Color(0.706084, 0.408439, 0.274016, 1) +metallic = 1.0 [sub_resource type="PlaneMesh" id="PlaneMesh_oqd8f"] [sub_resource type="BoxShape3D" id="BoxShape3D_h4g11"] size = Vector3(2, 2, 2) -[sub_resource type="ViewportTexture" id="ViewportTexture_h4g11"] -viewport_path = NodePath("DebugText") +[sub_resource type="MultiMesh" id="MultiMesh_3wpcb"] +transform_format = 1 +mesh = ExtResource("3_8mhad") + +[sub_resource type="PlaneMesh" id="PlaneMesh_f37ob"] +flip_faces = true [node name="GroundTile" type="Node3D"] script = ExtResource("1_uwxqs") +[node name="DebugText" type="Node3D" parent="."] +visible = false + +[node name="DebugTextViewport" type="SubViewport" parent="DebugText"] +size = Vector2i(50, 50) + +[node name="DebugTextLabel" type="Label" parent="DebugText/DebugTextViewport"] +offset_right = 40.0 +offset_bottom = 23.0 +text = "Hello world" + +[node name="DebugTextBillboard" type="Sprite3D" parent="DebugText"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0461426, 0.199493, 0.0660986) +texture = SubResource("ViewportTexture_h4g11") + [node name="Ground" type="MeshInstance3D" parent="."] -material_override = SubResource("StandardMaterial3D_oqd8f") +material_override = SubResource("StandardMaterial3D_f37ob") +cast_shadow = 0 mesh = SubResource("PlaneMesh_oqd8f") -[node name="GroundCollision" type="StaticBody3D" parent="."] +[node name="GroundCollision" type="StaticBody3D" parent="Ground"] -[node name="CollisionShape3D" type="CollisionShape3D" parent="GroundCollision"] +[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground/GroundCollision"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0) shape = SubResource("BoxShape3D_h4g11") [node name="fish2" parent="." instance=ExtResource("2_h4g11")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00713956, 0, 0.0313604) -[node name="DebugText" type="SubViewport" parent="."] -size = Vector2i(50, 50) +[node name="Grass" type="Node3D" parent="."] +script = ExtResource("3_224hx") -[node name="DebugTextLabel" type="Label" parent="DebugText"] -offset_right = 40.0 -offset_bottom = 23.0 -text = "Hello world" +[node name="GrassMultimesh" type="MultiMeshInstance3D" parent="Grass"] +material_override = ExtResource("3_f37ob") +cast_shadow = 0 +multimesh = SubResource("MultiMesh_3wpcb") +script = ExtResource("4_3wpcb") -[node name="Sprite3D" type="Sprite3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.0939356) -texture = SubResource("ViewportTexture_h4g11") +[node name="GrassTarget" type="MeshInstance3D" parent="Grass"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.0111763, 0) +mesh = SubResource("PlaneMesh_f37ob") + +[node name="Trees" type="Node3D" parent="."] +script = ExtResource("7_7lc7k") +tree_scenes = Array[PackedScene]([ExtResource("8_q0r4p"), ExtResource("6_7lc7k"), ExtResource("12_4hjaq"), ExtResource("8_q0r4p"), ExtResource("8_q0r4p"), ExtResource("8_q0r4p"), ExtResource("8_q0r4p")]) + +[node name="tree-trunk2" parent="." instance=ExtResource("7_jysav")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.554052, 0, 0.470964) diff --git a/Entities/GroundTile/assets/Dirt_05-256x256.png b/Entities/GroundTile/assets/Dirt_05-256x256.png new file mode 100644 index 0000000..52027ff --- /dev/null +++ b/Entities/GroundTile/assets/Dirt_05-256x256.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c47d70249ae3dc9578a43f5453b967d0394852c122b75696ba718a13782bbbd +size 139909 diff --git a/Entities/GroundTile/assets/Dirt_05-256x256.png.import b/Entities/GroundTile/assets/Dirt_05-256x256.png.import new file mode 100644 index 0000000..81fb606 --- /dev/null +++ b/Entities/GroundTile/assets/Dirt_05-256x256.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8pca7c2vlwaa" +path.s3tc="res://.godot/imported/Dirt_05-256x256.png-df3829dddfb4eeab82c63b0845e8a300.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://Entities/GroundTile/assets/Dirt_05-256x256.png" +dest_files=["res://.godot/imported/Dirt_05-256x256.png-df3829dddfb4eeab82c63b0845e8a300.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/Entities/GroundTile/ground_tile.gd b/Entities/GroundTile/ground_tile.gd index be5aa89..8285c3c 100644 --- a/Entities/GroundTile/ground_tile.gd +++ b/Entities/GroundTile/ground_tile.gd @@ -1,26 +1,29 @@ +# GroundTile.gd +class_name GroundTile extends Node3D -@onready var debug_text: Label = $DebugText/DebugTextLabel - +@onready var debug_text: Label = $DebugText/DebugTextViewport/DebugTextLabel var grid_x: int var grid_z: int -var cell_info: CellDataResource +var cell_info: CellDataResource = null: + set(value): + cell_info = value + if cell_info != null: + cell_info_updated.emit(value) + +var rng: RandomClass = RandomClass.new() + +signal cell_info_updated(value) func _ready() -> void: if cell_info != null: update_text_label() + rng.set_seed(cell_info.cell_seed) func set_grid_location(x, z) -> void: grid_x = x grid_z = z cell_info = MapData.get_map_data(grid_x, grid_z) - var debug_dict = {} - if cell_info.get_script(): - var script_properties = cell_info.get_script().get_script_property_list() - for prop in script_properties: - debug_dict[prop.name] = cell_info.get(prop.name) - Log.pr(debug_dict) - func update_text_label() -> void: debug_text.text = str(grid_x) + ', ' + str(grid_z) + ', ' + str(cell_info.cell_seed) diff --git a/Entities/GroundTile/scripts/grass.gd b/Entities/GroundTile/scripts/grass.gd new file mode 100644 index 0000000..7fe5c92 --- /dev/null +++ b/Entities/GroundTile/scripts/grass.gd @@ -0,0 +1,50 @@ +# GrassController.gd +extends Node3D +class_name GrassController + +# 229379 + +var parent_node: GroundTile = null +var grass_density: float = 0.5 +var grass_instance_range: int = 10 + +signal grass_data_ready() + +func _ready() -> void: + # Use call_deferred to ensure parent is fully ready + call_deferred("_setup_connections") + +func _setup_connections() -> void: + parent_node = get_parent() as GroundTile + if parent_node == null: + Log.pr("Error: Parent node is not a GroundTile!") + return + + parent_node.cell_info_updated.connect(_on_parent_data_changed) + + # Check if cell_info already exists and process it + if parent_node.cell_info != null: + _on_parent_data_changed(parent_node.cell_info) + +func _on_parent_data_changed(value): + if value == null: + return + + grass_density = value.vegetation_density + + update_grass_density() + + grass_data_ready.emit() + +func update_grass_density() -> void: + if parent_node == null or parent_node.rng == null: + return + + if grass_density > 0.8: + grass_instance_range = parent_node.rng.randi_range(100, 500) + elif grass_density > 0.6: + grass_instance_range = parent_node.rng.randi_range(30, 50) + elif grass_density > 0.3: + grass_instance_range = parent_node.rng.randi_range(5, 20) + else: + grass_instance_range = parent_node.rng.randi_range(0, 1) diff --git a/Entities/GroundTile/scripts/grass.gd.uid b/Entities/GroundTile/scripts/grass.gd.uid new file mode 100644 index 0000000..02ec37f --- /dev/null +++ b/Entities/GroundTile/scripts/grass.gd.uid @@ -0,0 +1 @@ +uid://cacp8ncwuofuj diff --git a/Entities/GroundTile/scripts/grass_multimesh.gd b/Entities/GroundTile/scripts/grass_multimesh.gd new file mode 100644 index 0000000..e799c79 --- /dev/null +++ b/Entities/GroundTile/scripts/grass_multimesh.gd @@ -0,0 +1,66 @@ +# GrassMultiMesh.gd (assuming this is your MultiMeshInstance3D script) +extends MultiMeshInstance3D + +var mm: MultiMesh +@onready var parent_node: GrassController + +func _ready() -> void: + # Use call_deferred to ensure proper initialization order + call_deferred("_setup_connections") + +func _setup_connections() -> void: + parent_node = get_parent() as GrassController + if parent_node == null: + Log.pr("Error: Parent node is not a GrassController!") + return + + parent_node.grass_data_ready.connect(_on_grass_data_ready) + Log.pr("Connected to grass_data_ready signal") + +func _on_grass_data_ready(): + Log.pr("Received grass_data_ready signal, setting up multimesh") + setup_multimesh() + +func setup_multimesh() -> void: + if parent_node == null: + Log.pr("Error: Parent node not available in setup_multimesh") + return + + # Load the mesh resource directly + var mesh = load("res://Stages/Test3D/assets/stylizedGrassMeshes/grass2_mesh.res") + if mesh == null: + Log.pr("Error: Could not load grass mesh") + return + + # Create new MultiMesh instance + mm = MultiMesh.new() + + # Configure the MultiMesh + mm.transform_format = MultiMesh.TRANSFORM_3D + mm.instance_count = parent_node.grass_instance_range + mm.mesh = mesh + + Log.pr("Setting up MultiMesh with " + str(mm.instance_count) + " instances") + + # Generate random positions for grass + for i in range(mm.instance_count): + var random_pos = Vector3( + randf_range(-1.0, 1.0), + 0.0, + randf_range(-1.0, 1.0) + ) + + var random_rotation = randf_range(0.0, TAU) + var basis = Basis(Vector3.UP, random_rotation) + + var random_scale = randf_range(0.05, 0.3) + basis = basis.scaled(Vector3(random_scale, random_scale, random_scale)) + + var tx = Transform3D(basis, random_pos) + mm.set_instance_transform(i, tx) + + # Assign the MultiMesh to this node + multimesh = mm + cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF + + Log.pr("MultiMesh setup complete with " + str(multimesh.instance_count) + " instances") \ No newline at end of file diff --git a/Entities/GroundTile/scripts/grass_multimesh.gd.uid b/Entities/GroundTile/scripts/grass_multimesh.gd.uid new file mode 100644 index 0000000..4af0730 --- /dev/null +++ b/Entities/GroundTile/scripts/grass_multimesh.gd.uid @@ -0,0 +1 @@ +uid://btju6b83mvgvk diff --git a/Entities/GroundTile/scripts/trees.gd b/Entities/GroundTile/scripts/trees.gd new file mode 100644 index 0000000..83734ff --- /dev/null +++ b/Entities/GroundTile/scripts/trees.gd @@ -0,0 +1,105 @@ +extends Node3D + +# Array of tree scenes to randomly choose from +@export var tree_scenes: Array[PackedScene] = [] +@export var spawn_area_size: Vector2 = Vector2(2.0, 2.0) # 2x2 area +@export var max_trees: int = 3 # Maximum possible trees +@export var min_distance: float = 0.5 # Minimum distance between trees + +var spawned_positions: Array[Vector3] = [] +var parent_ground_tile: GroundTile +var rng: RandomClass + +func _ready(): + # Get reference to parent GroundTile + parent_ground_tile = get_parent() as GroundTile + if parent_ground_tile: + # Connect to the signal + parent_ground_tile.cell_info_updated.connect(_on_cell_info_updated) + + # If cell_info already exists, spawn trees immediately + if parent_ground_tile.cell_info != null: + _on_cell_info_updated(parent_ground_tile.cell_info) + +func _on_cell_info_updated(cell_info: CellDataResource): + # Initialize RNG with the cell's seed for consistent results + rng = RandomClass.new() + rng.set_seed(cell_info.cell_seed) + + # Calculate number of trees based on vegetation_density + var tree_count = calculate_tree_count(cell_info.vegetation_density) + + # Spawn the trees + spawn_trees(tree_count) + +func calculate_tree_count(vegetation_density: float) -> int: + if vegetation_density < 0.7: + return 0 + + # vegetation_density should be between 0.0 and 1.0 + # Scale it to our max_trees range + var scaled_count = vegetation_density * max_trees + + # Round to nearest integer, but ensure at least 0 + return max(0, int(round(scaled_count))) + +func spawn_trees(tree_count: int): + if tree_scenes.is_empty(): + print("No tree scenes assigned!") + return + + if tree_count == 0: + print("No trees to spawn (vegetation_density too low)") + return + + # Clear any existing trees + clear_trees() + + # Try to place trees + var attempts = 0 + var max_attempts = tree_count * 10 # Prevent infinite loops + + while spawned_positions.size() < tree_count and attempts < max_attempts: + var pos = get_random_position() + + if is_position_valid(pos): + spawn_tree_at_position(pos) + spawned_positions.append(pos) + + attempts += 1 + + print("Spawned ", spawned_positions.size(), " trees") + +func get_random_position() -> Vector3: + var x = rng.randf_range(-spawn_area_size.x / 2, spawn_area_size.x / 2) + var z = rng.randf_range(-spawn_area_size.y / 2, spawn_area_size.y / 2) + return Vector3(x, 0, z) + +func is_position_valid(pos: Vector3) -> bool: + # Check if position is too close to existing trees + for existing_pos in spawned_positions: + if pos.distance_to(existing_pos) < min_distance: + return false + return true + +func spawn_tree_at_position(pos: Vector3): + # Pick a random tree scene using the seeded RNG + var random_index = rng.randi() % tree_scenes.size() + var random_tree_scene = tree_scenes[random_index] + var tree_instance = random_tree_scene.instantiate() + add_child(tree_instance) + tree_instance.position = pos + + # Optional: Add some random rotation using seeded RNG + tree_instance.rotation.y = rng.randf() * TAU + +func clear_trees(): + # Remove all existing tree children + for child in get_children(): + child.queue_free() + spawned_positions.clear() + +# Call this if you want to respawn trees manually +func respawn_trees(): + if parent_ground_tile and parent_ground_tile.cell_info: + _on_cell_info_updated(parent_ground_tile.cell_info) \ No newline at end of file diff --git a/Entities/GroundTile/scripts/trees.gd.uid b/Entities/GroundTile/scripts/trees.gd.uid new file mode 100644 index 0000000..6a38b3c --- /dev/null +++ b/Entities/GroundTile/scripts/trees.gd.uid @@ -0,0 +1 @@ +uid://cqko4m7cbxsfb diff --git a/Entities/Player/scripts/player.gd b/Entities/Player/scripts/player.gd index bcf498a..5e3c6b7 100644 --- a/Entities/Player/scripts/player.gd +++ b/Entities/Player/scripts/player.gd @@ -9,7 +9,8 @@ func _ready() -> void: position = Vector3.ZERO func _physics_process(delta): - %MultiMesh3D.set("instance_shader_parameters/player_position", position) + RenderingServer.global_shader_parameter_set("player_position", position) + %TileGround.update_chunks(position) # We create a local variable to store the input direction. diff --git a/Utilities/Random/RandomClass.gd b/Utilities/Random/RandomClass.gd new file mode 100644 index 0000000..ad74649 --- /dev/null +++ b/Utilities/Random/RandomClass.gd @@ -0,0 +1,56 @@ +extends Node + +class_name RandomClass + +var _rng: RandomNumberGenerator = RandomNumberGenerator.new() + +func _ready(): + randomize() + print("Global RNG initialized with seed: ", _rng.seed) + +# Set a specific seed for reproducible results +func set_seed(seed_value: int) -> void: + _rng.seed = seed_value + print("RNG seed set to: ", seed_value) + +# Randomize the seed (for non-reproducible results) +func randomize() -> void: + _rng.randomize() + print("RNG seed randomized to: ", _rng.seed) + +# Get the current seed value +func get_seed() -> int: + return _rng.seed + +# Get a random integer between min and max (inclusive) +func randi_range(min_value: int, max_value: int) -> int: + return _rng.randi_range(min_value, max_value) + +# Get a random float between 0.0 and 1.0 +func randf() -> float: + return _rng.randf() + +func randi() -> int: + return _rng.randi() + +# Get a random float between min and max +func randf_range(min_value: float, max_value: float) -> float: + return _rng.randf_range(min_value, max_value) + +# Get a random normalized vector +func random_unit_vector() -> Vector2: + return Vector2(randf_range(-1.0, 1.0), randf_range(-1.0, 1.0)).normalized() + +# Get a random point inside a circle with radius 1 +func random_point_in_circle() -> Vector2: + var r = sqrt(randf()) + var theta = randf() * 2.0 * PI + return Vector2(r * cos(theta), r * sin(theta)) + +# Get a random point inside a circle with specified radius +func random_point_in_circle_with_radius(radius: float) -> Vector2: + return random_point_in_circle() * radius + +# Get a random boolean value with specified probability +func random_bool(probability: float = 0.5) -> bool: + return randf() < probability diff --git a/Utilities/Random/RandomClass.gd.uid b/Utilities/Random/RandomClass.gd.uid new file mode 100644 index 0000000..9553bec --- /dev/null +++ b/Utilities/Random/RandomClass.gd.uid @@ -0,0 +1 @@ +uid://bbyxn7t840t6w diff --git a/grass.gdshader b/grass.gdshader index 11e584b..00d5dac 100644 --- a/grass.gdshader +++ b/grass.gdshader @@ -16,7 +16,7 @@ global uniform float wind_noise_size; // high values dont work well global uniform float wind_noise_speed; // Instance the Player Position through a GDScript in the _physics_process -instance uniform vec3 player_position; +global uniform vec3 player_position; void vertex() { vec3 world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; diff --git a/project.godot b/project.godot index 08935bf..5a3b996 100644 --- a/project.godot +++ b/project.godot @@ -61,17 +61,21 @@ jump={ wind_direction={ "type": "vec3", -"value": Vector3(5, 1, 5) +"value": Vector3(0.45, 0, -0.83) } wind_noise_size={ "type": "float", -"value": 0.1 +"value": 2.0 } wind_noise_speed={ "type": "float", -"value": 0.2 +"value": 0.1 } wind_strength={ "type": "float", -"value": 7.0 +"value": 0.5 +} +player_position={ +"type": "vec3", +"value": Vector3(0, 0, 0) } diff --git a/stages/Test3D/GrassMaterialOverride.tres b/stages/Test3D/GrassMaterialOverride.tres new file mode 100644 index 0000000..09945b0 --- /dev/null +++ b/stages/Test3D/GrassMaterialOverride.tres @@ -0,0 +1,16 @@ +[gd_resource type="ShaderMaterial" load_steps=3 format=3 uid="uid://b1miqvl8lus75"] + +[ext_resource type="Shader" uid="uid://dbduq0qcaxmyi" path="res://grass.gdshader" id="1_vnnwo"] + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_vnnwo"] + +[resource] +render_priority = 0 +shader = ExtResource("1_vnnwo") +shader_parameter/top_color = Color(0.102963, 0.465909, 0.382031, 1) +shader_parameter/bottom_color = Color(0.121494, 0.374954, 0.315972, 1) +shader_parameter/ambient_occlusion_factor = 0.0 +shader_parameter/specular_strength = 0.0 +shader_parameter/player_displacement_strength = 1.0 +shader_parameter/player_displacement_size = 1.0 +shader_parameter/wind_noise = SubResource("NoiseTexture2D_vnnwo") diff --git a/stages/Test3D/Test3d.tscn b/stages/Test3D/Test3d.tscn index 73ac44b..5ea690f 100644 --- a/stages/Test3D/Test3d.tscn +++ b/stages/Test3D/Test3d.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=65 format=4 uid="uid://bwsugg4p50fjr"] +[gd_scene load_steps=62 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"] @@ -7,7 +7,7 @@ [ext_resource type="Shader" uid="uid://bsemnmdracd4m" path="res://Common/shaders/outline.gdshader" id="4_feu7y"] [ext_resource type="PackedScene" uid="uid://c66kiiacr2bym" path="res://Stages/Test3D/assets/grass.glb" id="6_8ph61"] [ext_resource type="PackedScene" uid="uid://dg6v7qap28a5o" path="res://Stages/Test3D/assets/rock-a.glb" id="7_8537y"] -[ext_resource type="Shader" uid="uid://dbduq0qcaxmyi" path="res://grass.gdshader" id="7_hvb1l"] +[ext_resource type="Material" uid="uid://b1miqvl8lus75" path="res://Stages/Test3D/GrassMaterialOverride.tres" id="7_caaui"] [ext_resource type="PackedScene" uid="uid://ctw4ktjdpiva7" path="res://Stages/Test3D/assets/rock-b.glb" id="8_h8fbl"] [ext_resource type="ArrayMesh" uid="uid://r2imjo7o2734" path="res://Stages/Test3D/assets/stylizedGrassMeshes/grass2.res" id="8_xvexm"] [ext_resource type="PackedScene" uid="uid://nsnthin0ekva" path="res://Stages/Test3D/assets/rock-c.glb" id="9_rt72s"] @@ -40,7 +40,8 @@ script/source = "@tool extends DirectionalLight3D func _process(_delta): - (%PostProcessing as MeshInstance3D).mesh.surface_get_material(0).set_shader_parameter('light_direction', -global_basis.z) + pass + #(%PostProcessing as MeshInstance3D).mesh.surface_get_material(0).set_shader_parameter('light_direction', -global_basis.z) " [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_tfa5t"] @@ -374,26 +375,6 @@ material = SubResource("ShaderMaterial_tfa5t") flip_faces = true size = Vector2(2, 2) -[sub_resource type="FastNoiseLite" id="FastNoiseLite_hvb1l"] - -[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_xvexm"] -noise = SubResource("FastNoiseLite_hvb1l") - -[sub_resource type="ShaderMaterial" id="ShaderMaterial_ukp6m"] -render_priority = 0 -shader = ExtResource("7_hvb1l") -shader_parameter/top_color = Color(0.415686, 0.694118, 0.266667, 1) -shader_parameter/bottom_color = Color(0.176471, 0.333333, 0.0941176, 1) -shader_parameter/ambient_occlusion_factor = 0.5 -shader_parameter/specular_strength = 0.4 -shader_parameter/player_displacement_strength = 1.0 -shader_parameter/player_displacement_size = 0.53 -shader_parameter/wind_direction = Vector3(0.4, -0.3, 0.81) -shader_parameter/wind_strength = 0.3 -shader_parameter/wind_noise = SubResource("NoiseTexture2D_xvexm") -shader_parameter/wind_noise_size = 0.05 -shader_parameter/wind_noise_speed = 0.1 - [sub_resource type="MultiMesh" id="MultiMesh_hvb1l"] transform_format = 1 instance_count = 10000 @@ -785,7 +766,8 @@ script = ExtResource("2_sdmks") transform = Transform3D(1, 0, 0, 0, 1, -1.49012e-07, 0, 1.19209e-07, 1, 0.0410548, 0.237644, 3.45114) projection = 1 current = true -size = 3.0 +size = 4.0 +near = 0.01 far = 100.0 [node name="PostProcessing" type="MeshInstance3D" parent="SubViewportContainer/SubViewport/Player/CameraPivot/Camera3D"] @@ -803,7 +785,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.247314, 0, 0.404175) [node name="MultiMesh3D" type="MultiMeshInstance3D" parent="SubViewportContainer/SubViewport/Environment"] unique_name_in_owner = true -material_override = SubResource("ShaderMaterial_ukp6m") +material_override = ExtResource("7_caaui") cast_shadow = 0 multimesh = SubResource("MultiMesh_hvb1l") @@ -850,7 +832,7 @@ draw_pass_1 = SubResource("QuadMesh_hvb1l") [node name="OmniLight3D" type="OmniLight3D" parent="SubViewportContainer/SubViewport/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.779335 +light_energy = 0.763335 light_indirect_energy = 1.084 light_volumetric_fog_energy = 3.764 light_size = 0.105 diff --git a/stages/Test3D/assets/stylizedGrassMeshes/grass.res b/stages/Test3D/assets/stylizedGrassMeshes/grass.res index 1a2864c..25ccb3d 100644 Binary files a/stages/Test3D/assets/stylizedGrassMeshes/grass.res and b/stages/Test3D/assets/stylizedGrassMeshes/grass.res differ diff --git a/stages/Test3D/tile_map_test.gd b/stages/Test3D/tile_map_test.gd index 5ca3899..7b18533 100644 --- a/stages/Test3D/tile_map_test.gd +++ b/stages/Test3D/tile_map_test.gd @@ -3,108 +3,108 @@ extends Node3D @export var map_width: int = 500 @export var map_height: int = 500 @export var tile_size: float = 2.0 -@export var chunk_size: int = 2 +@export var chunk_size: int = 5 @export var view_distance: int = 2 -@export var tiles_per_frame: int = 1 # How many tiles to create per frame +@export var tiles_per_frame: int = 5 # How many tiles to create per frame var loaded_chunks: Dictionary = {} var player_position: Vector3 var last_chunk_pos: Vector2i = Vector2i(-999, -999) var loading_chunks: Dictionary = {} # Track chunks currently being loaded func _ready() -> void: - Log.pr('Testing optimized tile map generation') - create_tiles_chunked() + Log.pr('Testing optimized tile map generation') + create_tiles_chunked() func create_tiles_chunked() -> void: - Log.pr('Setting up chunked tile system...') - - var player = %Player - if player: - player_position = player.global_position - update_chunks(player_position) - else: - Log.pr("Player not found, loading chunks around origin") - update_chunks(Vector3.ZERO) + Log.pr('Setting up chunked tile system...') + + var player = %Player + if player: + player_position = player.global_position + update_chunks(player_position) + else: + Log.pr("Player not found, loading chunks around origin") + update_chunks(Vector3.ZERO) func update_chunks(player_pos: Vector3) -> void: - player_position = player_pos - - var current_chunk = Vector2i( - int(player_pos.x / (chunk_size * tile_size)), - int(player_pos.z / (chunk_size * tile_size)) - ) - - if current_chunk == last_chunk_pos: - return - - last_chunk_pos = current_chunk - Log.pr("CHUNK CHANGE - New chunk: ", current_chunk) - - # Determine which chunks should be loaded - var chunks_to_load: Array[Vector2i] = [] - for x in range(-view_distance, view_distance + 1): - for z in range(-view_distance, view_distance + 1): - chunks_to_load.append(current_chunk + Vector2i(x, z)) - - # LOADING new chunks - Log.pr("Chunks to load: ", chunks_to_load.size()) - for chunk_pos in chunks_to_load: - if chunk_pos not in loaded_chunks and chunk_pos not in loading_chunks: - Log.pr("Loading new: ", chunk_pos) - loading_chunks[chunk_pos] = true - load_chunk_async(chunk_pos) - - # UNLOADING far chunks - var chunks_to_unload: Array[Vector2i] = [] - for chunk_pos in loaded_chunks.keys(): - if chunk_pos not in chunks_to_load: - chunks_to_unload.append(chunk_pos) - - Log.pr("Chunks to unload: ", chunks_to_unload.size()) - for chunk_pos in chunks_to_unload: - Log.pr("Unloading: ", chunk_pos) - unload_chunk(chunk_pos) + player_position = player_pos + + var current_chunk = Vector2i( + int(player_pos.x / (chunk_size * tile_size)), + int(player_pos.z / (chunk_size * tile_size)) + ) + + if current_chunk == last_chunk_pos: + return + + last_chunk_pos = current_chunk + Log.pr("CHUNK CHANGE - New chunk: ", current_chunk) + + # Determine which chunks should be loaded + var chunks_to_load: Array[Vector2i] = [] + for x in range(-view_distance, view_distance + 1): + for z in range(-view_distance, view_distance + 1): + chunks_to_load.append(current_chunk + Vector2i(x, z)) + + # LOADING new chunks + Log.pr("Chunks to load: ", chunks_to_load.size()) + for chunk_pos in chunks_to_load: + if chunk_pos not in loaded_chunks and chunk_pos not in loading_chunks: + Log.pr("Loading new: ", chunk_pos) + loading_chunks[chunk_pos] = true + load_chunk_async(chunk_pos) + + # UNLOADING far chunks + var chunks_to_unload: Array[Vector2i] = [] + for chunk_pos in loaded_chunks.keys(): + if chunk_pos not in chunks_to_load: + chunks_to_unload.append(chunk_pos) + + Log.pr("Chunks to unload: ", chunks_to_unload.size()) + for chunk_pos in chunks_to_unload: + Log.pr("Unloading: ", chunk_pos) + unload_chunk(chunk_pos) func load_chunk_async(chunk_pos: Vector2i) -> void: - if not ground_tile: - Log.pr("ground_tile is null!") - loading_chunks.erase(chunk_pos) - return - - var chunk_node = Node3D.new() - chunk_node.name = "Chunk_%d_%d" % [chunk_pos.x, chunk_pos.y] - add_child(chunk_node) - - var start_x = chunk_pos.x * chunk_size * tile_size - (chunk_size * tile_size) / 2.0 - var start_z = chunk_pos.y * chunk_size * tile_size - (chunk_size * tile_size) / 2.0 - - var tiles_created = 0 - var tiles_this_frame = 0 - - for x in range(chunk_size): - for z in range(chunk_size): - var tile_instance = ground_tile.instantiate() - tile_instance.set_grid_location((chunk_pos.x * chunk_size) + x, (chunk_pos.y * chunk_size) + z) - tile_instance.position = Vector3( - start_x + (x * tile_size), - 0, - start_z + (z * tile_size) - ) - chunk_node.add_child(tile_instance) - tiles_created += 1 - tiles_this_frame += 1 - - # Yield after creating a certain number of tiles - if tiles_this_frame >= tiles_per_frame: - tiles_this_frame = 0 - await get_tree().process_frame - - Log.pr("Created ", tiles_created, " tiles in chunk ", chunk_pos) - loaded_chunks[chunk_pos] = chunk_node - loading_chunks.erase(chunk_pos) + if not ground_tile: + Log.pr("ground_tile is null!") + loading_chunks.erase(chunk_pos) + return + + var chunk_node = Node3D.new() + chunk_node.name = "Chunk_%d_%d" % [chunk_pos.x, chunk_pos.y] + add_child(chunk_node) + + var start_x = chunk_pos.x * chunk_size * tile_size - (chunk_size * tile_size) / 2.0 + var start_z = chunk_pos.y * chunk_size * tile_size - (chunk_size * tile_size) / 2.0 + + var tiles_created = 0 + var tiles_this_frame = 0 + + for x in range(chunk_size): + for z in range(chunk_size): + var tile_instance = ground_tile.instantiate() + tile_instance.set_grid_location((chunk_pos.x * chunk_size) + x, (chunk_pos.y * chunk_size) + z) + tile_instance.position = Vector3( + start_x + (x * tile_size), + 0, + start_z + (z * tile_size) + ) + chunk_node.add_child(tile_instance) + tiles_created += 1 + tiles_this_frame += 1 + + # Yield after creating a certain number of tiles + if tiles_this_frame >= tiles_per_frame: + tiles_this_frame = 0 + await get_tree().process_frame + + Log.pr("Created ", tiles_created, " tiles in chunk ", chunk_pos) + loaded_chunks[chunk_pos] = chunk_node + loading_chunks.erase(chunk_pos) func unload_chunk(chunk_pos: Vector2i) -> void: - if chunk_pos in loaded_chunks: - Log.pr("Unloading chunk: ", chunk_pos) - loaded_chunks[chunk_pos].queue_free() - loaded_chunks.erase(chunk_pos) \ No newline at end of file + if chunk_pos in loaded_chunks: + Log.pr("Unloading chunk: ", chunk_pos) + loaded_chunks[chunk_pos].queue_free() + loaded_chunks.erase(chunk_pos)