feat: implemented chunking

This commit is contained in:
Sara Gerretsen 2025-11-19 18:46:38 +01:00
parent 823d70a93c
commit f5a78e10c7
6 changed files with 188 additions and 45 deletions

View file

@ -2,9 +2,11 @@
#include "core/math/math_funcs.h"
#include "core/math/rect2.h"
#include "core/object/class_db.h"
#include "core/object/object.h"
#include "core/templates/local_vector.h"
#include "scene/resources/surface_tool.h"
#include "terrain_editor/macros.h"
#include "terrain_editor/terrain_chunk.h"
#include "terrain_editor/terrain_primitive.h"
#include <limits>
@ -16,15 +18,55 @@ void TerrainMeshGenerator::_bind_methods() {
BIND_HPROPERTY(Variant::OBJECT, vertex_color_gradient, PROPERTY_HINT_RESOURCE_TYPE, "Gradient");
BIND_PROPERTY(Variant::FLOAT, color_gradient_start_height);
BIND_PROPERTY(Variant::FLOAT, color_gradient_end_height);
BIND_PROPERTY(Variant::FLOAT, chunk_size);
BIND_PROPERTY(Variant::INT, lod1_detail);
BIND_PROPERTY(Variant::INT, chunk_count);
BIND_HPROPERTY(Variant::OBJECT, material, PROPERTY_HINT_RESOURCE_TYPE, "Material");
ADD_SIGNAL(MethodInfo(sig_primitives_changed));
ADD_SIGNAL(MethodInfo(sig_primitive_list_changed, PropertyInfo(Variant::ARRAY, "array", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:TerrainPrimitive", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE))));
ClassDB::bind_method(D_METHOD("generate_grid", "area", "out_mesh", "side_points"), &self_type::generate_grid);
}
void TerrainMeshGenerator::ready() {
if (this->chunks.is_empty()) {
rebuild_chunks();
}
}
void TerrainMeshGenerator::on_configuration_changed() {
emit_signal(sig_primitives_changed);
}
void TerrainMeshGenerator::_notification(int what) {
switch (what) {
default:
return;
case NOTIFICATION_READY:
ready();
return;
}
}
void TerrainMeshGenerator::rebuild_chunks() {
for (TerrainChunk *chunk : this->chunks) {
chunk->queue_free();
}
this->chunks.clear();
Vector3 origin{ -Vector3{ (float)chunks_per_side, 0, (float)chunks_per_side } * this->chunk_size / 2 };
for (size_t chunk_y{ 0 }; chunk_y < this->chunks_per_side; ++chunk_y) {
for (size_t chunk_x{ 0 }; chunk_x < this->chunks_per_side; ++chunk_x) {
TerrainChunk *chunk{ memnew(TerrainChunk) };
chunk->set_size(this->chunk_size);
chunk->set_lod1_detail(this->lod1_detail);
chunk->set_material_override(this->material);
this->chunks.push_back(chunk);
Vector3 offset{ Vector3{ (float)chunk_x, 0.f, (float)chunk_y } * this->chunk_size };
chunk->set_position(origin + offset);
add_child(chunk);
}
}
}
Color TerrainMeshGenerator::color_at_height(float height) const {
float const mapped{ Math::remap(height, this->color_gradient_start_height, this->color_gradient_end_height, 0.f, 1.f) };
return this->vertex_color_gradient.is_valid()
@ -69,6 +111,7 @@ void TerrainMeshGenerator::generate_grid(Rect2 area, Ref<ArrayMesh> mesh, size_t
mesh->clear_surfaces();
surface->clear();
Vector2 point_distance{ area.size / (float)side_points };
++side_points;
Vector2 at{ area.position };
surface->begin(Mesh::PRIMITIVE_TRIANGLES);
for (size_t xpoint{ 0 }; xpoint < side_points; ++xpoint) {
@ -76,7 +119,7 @@ void TerrainMeshGenerator::generate_grid(Rect2 area, Ref<ArrayMesh> mesh, size_t
float const height{ evaluate_point(at) };
surface->set_color(color_at_height(height));
surface->set_uv({ at / area.size });
surface->add_vertex({ at.x, height, at.y });
surface->add_vertex({ at.x - area.position.x, height, at.y - area.position.y });
at.y += point_distance.y;
}
at.y = area.position.y;
@ -150,3 +193,42 @@ void TerrainMeshGenerator::set_color_gradient_end_height(float value) {
float TerrainMeshGenerator::get_color_gradient_end_height() const {
return this->color_gradient_end_height;
}
void TerrainMeshGenerator::set_chunk_size(float size) {
this->chunk_size = size;
rebuild_chunks();
}
float TerrainMeshGenerator::get_chunk_size() const {
return this->chunk_size;
}
void TerrainMeshGenerator::set_lod1_detail(int detail) {
if (detail != this->lod1_detail) {
this->lod1_detail = detail;
rebuild_chunks();
}
}
int TerrainMeshGenerator::get_lod1_detail() const {
return this->lod1_detail;
}
void TerrainMeshGenerator::set_chunk_count(int num) {
if (num != this->chunks_per_side) {
this->chunks_per_side = num;
rebuild_chunks();
}
}
int TerrainMeshGenerator::get_chunk_count() const {
return this->chunks_per_side;
}
void TerrainMeshGenerator::set_material(Ref<Material> material) {
this->material = material;
for (TerrainChunk *chunk : this->chunks) {
chunk->set_material_override(material);
}
}
Ref<Material> TerrainMeshGenerator::get_material() const {
return this->material;
}