From b5bf7619e6762ea3617e66c2386cf2754e15c5fe Mon Sep 17 00:00:00 2001 From: Dan Baker Date: Tue, 24 Jun 2025 13:14:21 +0100 Subject: [PATCH] Implements procedural ground tile generation Adds procedural ground tile generation with chunking for improved performance. Includes: - Ground tile entity with debug text and cell information - Grass and tree placement based on cell data - Ground shader for visual representation - Chunk loading and unloading system based on player position --- Entities/GroundTile/GroundTile.gdshader | 16 ++ Entities/GroundTile/GroundTile.gdshader.uid | 1 + Entities/GroundTile/GroundTile.tscn | 75 ++++++-- .../GroundTile/assets/Dirt_05-256x256.png | 3 + .../assets/Dirt_05-256x256.png.import | 35 ++++ Entities/GroundTile/ground_tile.gd | 23 ++- Entities/GroundTile/scripts/grass.gd | 50 +++++ Entities/GroundTile/scripts/grass.gd.uid | 1 + .../GroundTile/scripts/grass_multimesh.gd | 66 +++++++ .../GroundTile/scripts/grass_multimesh.gd.uid | 1 + Entities/GroundTile/scripts/trees.gd | 105 ++++++++++ Entities/GroundTile/scripts/trees.gd.uid | 1 + Entities/Player/scripts/player.gd | 3 +- Utilities/Random/RandomClass.gd | 56 ++++++ Utilities/Random/RandomClass.gd.uid | 1 + grass.gdshader | 2 +- project.godot | 12 +- stages/Test3D/GrassMaterialOverride.tres | 16 ++ stages/Test3D/Test3d.tscn | 34 +--- .../assets/stylizedGrassMeshes/grass.res | Bin 6408 -> 3460 bytes stages/Test3D/tile_map_test.gd | 180 +++++++++--------- 21 files changed, 532 insertions(+), 149 deletions(-) create mode 100644 Entities/GroundTile/GroundTile.gdshader create mode 100644 Entities/GroundTile/GroundTile.gdshader.uid create mode 100644 Entities/GroundTile/assets/Dirt_05-256x256.png create mode 100644 Entities/GroundTile/assets/Dirt_05-256x256.png.import create mode 100644 Entities/GroundTile/scripts/grass.gd create mode 100644 Entities/GroundTile/scripts/grass.gd.uid create mode 100644 Entities/GroundTile/scripts/grass_multimesh.gd create mode 100644 Entities/GroundTile/scripts/grass_multimesh.gd.uid create mode 100644 Entities/GroundTile/scripts/trees.gd create mode 100644 Entities/GroundTile/scripts/trees.gd.uid create mode 100644 Utilities/Random/RandomClass.gd create mode 100644 Utilities/Random/RandomClass.gd.uid create mode 100644 stages/Test3D/GrassMaterialOverride.tres 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 1a2864ca7cd8505670fb2e3b8bd96f36458d169e..25ccb3d0e371f88c573fb6ace4100d4fe1bbe913 100644 GIT binary patch literal 3460 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 literal 6408 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 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)