feat: caching meshes and heightmaps

This commit is contained in:
Sara Gerretsen 2026-04-05 18:09:17 +02:00
parent 7dd18810c3
commit b738f076c2
8 changed files with 66 additions and 124 deletions

View file

@ -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

View file

@ -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<TerrainChunkMesh>(var) }) {
this->meshes.push_back(mesh);
mesh->set_terrain(this);
}
if (TerrainModifier * mod{ cast_to<TerrainModifier>(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<TerrainChunkMesh>(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;
}

View file

@ -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;
};

View file

@ -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;
}
}

View file

@ -44,6 +44,7 @@ private:
public:
GET_SET_FNS(Rect2, bounds);
GET_SET_FNS(Terrain *, terrain);
GET_SET_FNS(Ref<HeightMapShape3D>, shape);
GET_SET_FNS(size_t, detail);
GET_SET_FNS(size_t, size);
};

View file

@ -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"

Binary file not shown.

View file

@ -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)