diff --git a/modules/terrain/TODO.org b/modules/terrain/TODO.org index 68affade..11cdf692 100644 --- a/modules/terrain/TODO.org +++ b/modules/terrain/TODO.org @@ -1,4 +1,4 @@ -- [ ] Cache chunk meshes +- [x] Cache chunk meshes - [ ] Noise modifier - [ ] Min/Max modifier - [ ] Only load Defined chunks @@ -6,3 +6,4 @@ - [ ] Texturing step - [ ] Use Semaphores in mesh gen multi-threading - [ ] Separate files for terrain modifiers +- [ ] Stop threads when generation finishes diff --git a/modules/terrain/terrain.cpp b/modules/terrain/terrain.cpp index e09b054e..c41eaef5 100644 --- a/modules/terrain/terrain.cpp +++ b/modules/terrain/terrain.cpp @@ -6,8 +6,8 @@ void Terrain::_bind_methods() { BIND_HPROPERTY(Variant::OBJECT, mesh_material, PROPERTY_HINT_RESOURCE_TYPE, "Material"); BIND_PROPERTY(Variant::INT, side_length); BIND_PROPERTY(Variant::INT, chunk_size); - BIND_PROPERTY(Variant::INT, detail); BIND_PROPERTY(Variant::INT, thread_count); + BIND_HPROPERTY(Variant::ARRAY, terrain_meshes, PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:TerrainMeshChunk", Variant::OBJECT, PROPERTY_HINT_NODE_TYPE), PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY); } void Terrain::child_order_changed() { @@ -85,15 +85,31 @@ void Terrain::_notification(int what) { switch (what) { default: return; - case NOTIFICATION_ENTER_TREE: - if (!is_ready()) { - connect("child_order_changed", callable_mp(this, &self_type::child_order_changed)); + case NOTIFICATION_CHILD_ORDER_CHANGED: + if (is_ready()) { + this->child_order_changed(); } return; - case NOTIFICATION_READY: - construct_chunk_grid(); - synchronous_generate_terrain(); + case NOTIFICATION_READY: { + this->meshes.clear(); + this->modifiers.clear(); + for (Variant var : get_children()) { + if (TerrainChunkMesh * mesh{ cast_to(var) }) { + this->meshes.push_back(mesh); + mesh->set_terrain(this); + } + if (TerrainModifier * mod{ cast_to(var) }) { + this->modifiers.push_back(mod); + mod->set_terrain(this); + } + } + size_t expected_size{ this->side_length / this->chunk_size }; + if (this->meshes.size() != expected_size * expected_size) { + construct_chunk_grid(); + synchronous_generate_terrain(); + } return; + } case NOTIFICATION_PROCESS: update_meshes(); update_threads(); @@ -166,8 +182,9 @@ void Terrain::construct_chunk_grid() { chunk->set_terrain(this); chunk->set_material_override(this->mesh_material); chunk->set_position(origin + Vector3{ (float)this->chunk_size * (float)x, 0.f, (float)this->chunk_size * (float)y }); + chunk->set_name(vformat("Chunk%dx%d", x, y)); add_child(chunk); - chunk->set_owner(this); + chunk->set_owner(get_owner()); this->meshes.push_back(chunk); this->workload.push_back(chunk); } @@ -269,3 +286,22 @@ void Terrain::set_thread_count(size_t num) { size_t Terrain::get_thread_count() const { return this->threads.size(); } + +void Terrain::set_terrain_meshes(Array array) { + return; + this->meshes.clear(); + for (Variant var : array) { + if (TerrainChunkMesh * mesh{ cast_to(var) }) { + mesh->set_terrain(this); + this->meshes.push_back(mesh); + } + } +} + +Array Terrain::get_terrain_meshes() const { + Array a{}; + for (TerrainChunkMesh *mesh : this->meshes) { + a.push_back(mesh); + } + return a; +} diff --git a/modules/terrain/terrain.h b/modules/terrain/terrain.h index 7062fc26..b2e5a264 100644 --- a/modules/terrain/terrain.h +++ b/modules/terrain/terrain.h @@ -55,4 +55,6 @@ public: size_t get_detail() const; void set_thread_count(size_t num); size_t get_thread_count() const; + void set_terrain_meshes(Array array); + Array get_terrain_meshes() const; }; diff --git a/modules/terrain/terrain_chunk.cpp b/modules/terrain/terrain_chunk.cpp index ab09e534..ac81ac37 100644 --- a/modules/terrain/terrain_chunk.cpp +++ b/modules/terrain/terrain_chunk.cpp @@ -1,6 +1,7 @@ #include "terrain_chunk.h" #include "core/math/math_defs.h" #include "core/math/math_funcs.h" +#include "core/object/object.h" #include "core/variant/variant.h" #include "scene/3d/physics/collision_shape_3d.h" #include "scene/3d/physics/static_body_3d.h" @@ -8,7 +9,10 @@ #include "scene/resources/surface_tool.h" #include "terrain/terrain.h" -void TerrainChunkMesh::_bind_methods() {} +void TerrainChunkMesh::_bind_methods() { + BIND_HPROPERTY(Variant::OBJECT, shape, PROPERTY_HINT_RESOURCE_TYPE, "HeightMapShape3D", PROPERTY_USAGE_READ_ONLY | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE); + BIND_HPROPERTY(Variant::INT, size, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_READ_ONLY | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE); +} void TerrainChunkMesh::ready() { this->position_buffer = get_global_position(); @@ -22,11 +26,15 @@ void TerrainChunkMesh::ready() { this->body->set_owner(this); ERR_FAIL_COND_EDMSG(this->collider == nullptr, "Failed to instantiate CollisionShape3D"); this->collider->set_owner(this); - this->shape = memnew(HeightMapShape3D); + if (this->shape.is_null()) { + this->shape = memnew(HeightMapShape3D); + this->shape->set_map_depth(heightmap_side_length()); + this->shape->set_map_width(heightmap_side_length()); + } else { + this->heightmap.append_array(this->shape->get_map_data()); + } ERR_FAIL_COND_EDMSG(!this->shape.is_valid(), "Failed to instantiate HeightMapShape3D"); this->collider->set_shape(this->shape); - this->shape->set_map_depth(heightmap_side_length()); - this->shape->set_map_width(heightmap_side_length()); } void TerrainChunkMesh::generate_vertices() { @@ -85,8 +93,10 @@ void TerrainChunkMesh::_notification(int what) { switch (what) { default: return; - case NOTIFICATION_READY: - ready(); + case NOTIFICATION_ENTER_TREE: + if (!is_ready()) { + ready(); + } return; } } diff --git a/modules/terrain/terrain_chunk.h b/modules/terrain/terrain_chunk.h index 64b59218..fb427e62 100644 --- a/modules/terrain/terrain_chunk.h +++ b/modules/terrain/terrain_chunk.h @@ -44,6 +44,7 @@ private: public: GET_SET_FNS(Rect2, bounds); GET_SET_FNS(Terrain *, terrain); + GET_SET_FNS(Ref, shape); GET_SET_FNS(size_t, detail); GET_SET_FNS(size_t, size); }; diff --git a/project/project.godot b/project/project.godot index 477ade1f..b135cc22 100644 --- a/project/project.godot +++ b/project/project.godot @@ -15,7 +15,7 @@ compatibility/default_parent_skeleton_in_mesh_instance_3d=true [application] config/name="authority" -run/main_scene="uid://1qvpc2ej32pd" +run/main_scene="uid://ct2wadj5e8xsl" config/features=PackedStringArray("4.6", "Forward Plus") config/icon="res://icon.svg" diff --git a/project/scenes/terrain_test.scn b/project/scenes/terrain_test.scn new file mode 100644 index 00000000..d294613a Binary files /dev/null and b/project/scenes/terrain_test.scn differ diff --git a/project/scenes/terrain_test.tscn b/project/scenes/terrain_test.tscn deleted file mode 100644 index 107a7628..00000000 --- a/project/scenes/terrain_test.tscn +++ /dev/null @@ -1,108 +0,0 @@ -[gd_scene format=3 uid="uid://d2w73ie2k01xg"] - -[ext_resource type="Material" uid="uid://b2gybv8h8h0u0" path="res://assets/style/terrain_material.tres" id="1_w3uoq"] -[ext_resource type="PackedScene" uid="uid://bedet0our63p0" path="res://objects/player_vehicle.tscn" id="2_o3i6r"] - -[sub_resource type="Curve" id="Curve_o3i6r"] -_limits = [0.0, 1.0, 0.0, 30.0] -_data = [Vector2(0, 1), 0.0, -0.039764207, 0, 1, Vector2(18.735312, 0.25500518), -0.023317037, -0.023317037, 0, 0, Vector2(30, 0), -0.008611488, 0.0, 0, 0] -point_count = 3 - -[sub_resource type="BoxMesh" id="BoxMesh_kbmr5"] - -[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_8mrfl"] -sky_top_color = Color(0.28, 0.33600003, 0.56, 1) -sky_horizon_color = Color(0.6590071, 0.7017287, 0.7452071, 1) -ground_bottom_color = Color(0.18026966, 0.32224965, 0.43171933, 1) -ground_horizon_color = Color(0.6590071, 0.7017287, 0.7452071, 1) - -[sub_resource type="Sky" id="Sky_m8orc"] -sky_material = SubResource("ProceduralSkyMaterial_8mrfl") - -[sub_resource type="Environment" id="Environment_1b7vx"] -background_mode = 4 -sky = SubResource("Sky_m8orc") -ambient_light_source = 2 -ambient_light_color = Color(1, 1, 1, 1) -ambient_light_energy = 0.77 -reflected_light_source = 1 -tonemap_mode = 2 -ssao_radius = 16.0 -ssao_intensity = 9.65 -ssao_power = 0.21446471 -ssao_detail = 0.0 -ssao_horizon = 0.57 -ssil_radius = 16.0 -ssil_intensity = 0.65 -fog_enabled = true -fog_mode = 1 -fog_light_color = Color(0.49139997, 0.60203, 0.78, 1) -fog_light_energy = 0.5 -fog_density = 0.0403 -fog_sky_affect = 0.0 -fog_depth_curve = 16.856052 -fog_depth_begin = 20.0 -fog_depth_end = 300.0 - -[sub_resource type="CameraAttributesPractical" id="CameraAttributesPractical_7eqww"] -dof_blur_far_enabled = true -dof_blur_far_distance = 1000.0 -dof_blur_far_transition = 250.0 -dof_blur_near_enabled = true -dof_blur_near_distance = 1.0 -dof_blur_amount = 0.15 - -[sub_resource type="Compositor" id="Compositor_n0ica"] - -[sub_resource type="SphereMesh" id="SphereMesh_o3i6r"] -flip_faces = true -radius = 750.0 -height = 1500.0 - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_chm2y"] -shading_mode = 0 -diffuse_mode = 3 -specular_mode = 2 -disable_ambient_light = true -disable_fog = true -disable_specular_occlusion = true -albedo_color = Color(0.37199998, 0.5951999, 0.93, 1) - -[node name="Node3D" type="Node3D" unique_id=289500437] - -[node name="Terrain" type="Terrain" parent="." unique_id=1169843565] -mesh_material = ExtResource("1_w3uoq") -side_length = 1000 -chunk_size = 100 -thread_count = 5 - -[node name="TerrainModifierComposite" type="TerrainModifierComposite" parent="Terrain" unique_id=831035468] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 93.48691, 13.848653, 332.4415) - -[node name="TerrainModifierDistance" type="TerrainModifierDistance" parent="Terrain/TerrainModifierComposite" unique_id=1223634269] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4.1339216, 0) -distance_weight_curve = SubResource("Curve_o3i6r") - -[node name="TerrainModifierDistance2" type="TerrainModifierDistance" parent="Terrain/TerrainModifierComposite" unique_id=517982974] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4.1339216, 17.476501) -distance_weight_curve = SubResource("Curve_o3i6r") - -[node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=1089775425] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 62.376347, 0.5, 364.3086) -mesh = SubResource("BoxMesh_kbmr5") - -[node name="PlayerVehicle" parent="." unique_id=2037675333 instance=ExtResource("2_o3i6r")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 59.221, 0.03404631, 364.57117) - -[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=1509403058] -environment = SubResource("Environment_1b7vx") -camera_attributes = SubResource("CameraAttributesPractical_7eqww") -compositor = SubResource("Compositor_n0ica") - -[node name="SkySphere" type="MeshInstance3D" parent="." unique_id=56834935] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 543.9732, 3.9775777, 555.09717) -mesh = SubResource("SphereMesh_o3i6r") -surface_material_override/0 = SubResource("StandardMaterial3D_chm2y") - -[node name="Camera3D" type="Camera3D" parent="." unique_id=241002743] -transform = Transform3D(-0.13388503, 0.50896627, -0.8503106, 0.0791636, 0.86078644, 0.5027721, 0.9878299, 0, -0.15553802, 388.02707, 99.978836, 697.3086)