From 1e44fcd09fe7604c2f516142947476e12dd3613b Mon Sep 17 00:00:00 2001 From: Sara Date: Wed, 25 Feb 2026 22:42:07 +0100 Subject: [PATCH] feat: apply_mesh for chunks is smeared over frames --- modules/terrain/terrain.cpp | 27 +++++++++++++++++++++++++++ modules/terrain/terrain.h | 8 +++++++- modules/terrain/terrain_chunk.cpp | 12 +++++++----- modules/terrain/terrain_chunk.h | 2 +- project/scenes/terrain_test.tscn | 9 +++++---- 5 files changed, 47 insertions(+), 11 deletions(-) diff --git a/modules/terrain/terrain.cpp b/modules/terrain/terrain.cpp index 632075a8..b1c01738 100644 --- a/modules/terrain/terrain.cpp +++ b/modules/terrain/terrain.cpp @@ -19,6 +19,23 @@ void Terrain::child_order_changed() { } } +void Terrain::update_meshes() { + size_t num{ 1 }; + this->dirty_meshes_lock.lock(); + num = num > this->dirty_meshes.size() ? this->dirty_meshes.size() : num; + this->dirty_meshes_lock.unlock(); + for (size_t i{ 0 }; i < num; i++) { + this->dirty_meshes_lock.lock(); + TerrainChunkMesh *mesh{ this->dirty_meshes[0] }; + this->dirty_meshes.remove_at(0); + this->dirty_meshes_lock.unlock(); + mesh->apply_new_mesh(); + } + if (this->dirty_meshes.is_empty()) { + set_process(false); + } +} + void Terrain::_notification(int what) { switch (what) { default: @@ -31,6 +48,9 @@ void Terrain::_notification(int what) { case NOTIFICATION_READY: construct_chunk_grid(); return; + case NOTIFICATION_PROCESS: + update_meshes(); + return; case NOTIFICATION_EXIT_TREE: this->workload_lock.lock(); this->threads_stop = true; @@ -116,6 +136,13 @@ void Terrain::push_changed(Rect2 area) { } } +void Terrain::mesh_dirty(TerrainChunkMesh *mesh) { + this->dirty_meshes_lock.lock(); + this->dirty_meshes.push_back(mesh); + callable_mp(cast_to(this), &self_type::set_process).call_deferred(true); + this->dirty_meshes_lock.unlock(); +} + void Terrain::set_side_length(size_t length) { this->side_length = length; if (is_inside_tree()) { diff --git a/modules/terrain/terrain.h b/modules/terrain/terrain.h index bfa10944..64177a7f 100644 --- a/modules/terrain/terrain.h +++ b/modules/terrain/terrain.h @@ -12,6 +12,7 @@ class Terrain : public Node { GDCLASS(Terrain, Node); static void _bind_methods(); void child_order_changed(); + void update_meshes(); protected: void _notification(int what); @@ -21,11 +22,16 @@ public: void construct_chunk_grid(); float height_at(Vector2 world_coordinate); void push_changed(Rect2 area); + void mesh_dirty(TerrainChunkMesh *mesh); private: Vector workload{}; - Mutex workload_lock; bool threads_stop{ false }; + Mutex workload_lock; + + Vector dirty_meshes{}; + Mutex dirty_meshes_lock{}; + Vector meshes{}; Vector modifiers{}; LocalVector threads{}; diff --git a/modules/terrain/terrain_chunk.cpp b/modules/terrain/terrain_chunk.cpp index f3c9a6a8..0f4d735f 100644 --- a/modules/terrain/terrain_chunk.cpp +++ b/modules/terrain/terrain_chunk.cpp @@ -5,10 +5,6 @@ void TerrainChunkMesh::_bind_methods() {} -void TerrainChunkMesh::apply_new_mesh() { - set_mesh(this->new_mesh); -} - void TerrainChunkMesh::generate_vertices() { ERR_FAIL_COND_EDMSG(this->terrain == nullptr, "TerrainChunkMesh::generate_vertices: no terrain assigned"); ERR_FAIL_COND_EDMSG(this->size <= 0.f, "TerrainChunkMesh::generate_vertices: size <= 0"); @@ -68,6 +64,12 @@ void TerrainChunkMesh::_notification(int what) { } } +void TerrainChunkMesh::apply_new_mesh() { + this->lock.lock(); + set_mesh(this->new_mesh); + this->lock.unlock(); +} + void TerrainChunkMesh::update_mesh() { ERR_FAIL_COND_EDMSG(this->size <= 0.f, "TerrainChunkMesh::generate: size <= 0"); ERR_FAIL_COND_EDMSG(points_per_side() <= 0, "TerrainChunkMesh::generate: points per side <= 0"); @@ -80,8 +82,8 @@ void TerrainChunkMesh::update_mesh() { this->surface->generate_tangents(); this->new_mesh = memnew(ArrayMesh); this->surface->commit(this->new_mesh); - callable_mp(this, &self_type::apply_new_mesh).call_deferred(); this->lock.unlock(); + this->terrain->mesh_dirty(this); } size_t TerrainChunkMesh::points_per_side() const { diff --git a/modules/terrain/terrain_chunk.h b/modules/terrain/terrain_chunk.h index 5e0ab458..2e9ea49e 100644 --- a/modules/terrain/terrain_chunk.h +++ b/modules/terrain/terrain_chunk.h @@ -10,7 +10,6 @@ class Terrain; class TerrainChunkMesh : public MeshInstance3D { GDCLASS(TerrainChunkMesh, MeshInstance3D); static void _bind_methods(); - void apply_new_mesh(); void generate_vertices(); void generate_faces(); @@ -18,6 +17,7 @@ protected: void _notification(int what); public: + void apply_new_mesh(); void update_mesh(); size_t points_per_side() const; diff --git a/project/scenes/terrain_test.tscn b/project/scenes/terrain_test.tscn index aa0c90aa..1371bb58 100644 --- a/project/scenes/terrain_test.tscn +++ b/project/scenes/terrain_test.tscn @@ -20,8 +20,8 @@ point_count = 4 [sub_resource type="Curve" id="Curve_w3uoq"] [sub_resource type="Curve" id="Curve_chm2y"] -_limits = [0.0, 1.0, 0.0, 300.0] -_data = [Vector2(0, 1), 0.0, -0.0043322877, 0, 0, Vector2(92.849304, 0.5972115), -0.0058290004, -0.0058290004, 0, 0, Vector2(300, 0), 0.00017739221, -0.05797184, 0, 0] +_limits = [0.0, 1.0, 0.0, 200.0] +_data = [Vector2(0, 1), 0.0, -0.0043322877, 0, 0, Vector2(92.849304, 0.5972115), -0.0058290004, -0.0058290004, 0, 0, Vector2(199.46088, 0), 0.00017739221, -0.05797184, 0, 0] point_count = 3 [sub_resource type="Curve" id="Curve_o3i6r"] @@ -48,16 +48,17 @@ environment = SubResource("Environment_o3i6r") [node name="Terrain" type="Terrain" parent="." unique_id=1169843565] side_length = 1000 +chunk_size = 200 thread_count = 2 [node name="TerrainModifierDistance" type="TerrainModifierDistance" parent="Terrain" unique_id=1885116624] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 544.8632, 188.56836, 713.1275) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 544.8632, 213.3872, 613.2415) blend_distance = 4.0 distance_weight_curve = SubResource("Curve_kbmr5") distance_height_curve = SubResource("Curve_w3uoq") [node name="TerrainModifierDistance3" type="TerrainModifierDistance" parent="Terrain" unique_id=1846439541] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 534.7505, 273.91986, 453.44415) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 534.7505, 330.91986, 385.44415) blend_distance = 4.0 distance_weight_curve = SubResource("Curve_chm2y") distance_height_curve = SubResource("Curve_o3i6r")