feat: lazy loading of terrain chunk LODs
This commit is contained in:
parent
90c46e30d2
commit
2a3eeef522
4 changed files with 48 additions and 28 deletions
|
|
@ -21,11 +21,21 @@ void TerrainChunk::ready() {
|
|||
process_lod();
|
||||
}
|
||||
|
||||
void TerrainChunk::generate_lod(size_t lod) {
|
||||
MeshStatus status{ this->meshes.get(lod) };
|
||||
size_t base_detail{ lod == 0 ? this->lod0_detail : this->lod0_detail / (2 * lod + lod) };
|
||||
base_detail = base_detail > 1 ? base_detail : 1;
|
||||
Vector3 const position{ get_global_position() };
|
||||
this->generator->push_task({ { position.x, position.z }, { this->size, this->size } }, status.mesh, base_detail > 1 ? base_detail : 1, callable_mp(this, &self_type::lod_generated).bind(lod));
|
||||
status.flag = MESH_DISPATCHED;
|
||||
this->meshes.set(lod, status);
|
||||
}
|
||||
|
||||
void TerrainChunk::on_terrain_changed() {
|
||||
if (this->generator) {
|
||||
Vector3 const position{ get_global_position() };
|
||||
this->meshes.resize_initialized(3);
|
||||
size_t lod{ 0 };
|
||||
if (this->meshes.size() != this->lod_count) {
|
||||
this->meshes.resize_initialized(this->lod_count);
|
||||
}
|
||||
if (this->collisions) {
|
||||
this->collisions->queue_free();
|
||||
this->collisions = nullptr;
|
||||
|
|
@ -34,28 +44,31 @@ void TerrainChunk::on_terrain_changed() {
|
|||
if (!status.mesh.is_valid()) {
|
||||
status.mesh.instantiate();
|
||||
}
|
||||
size_t base_detail{ lod == 0 ? this->lod0_detail : this->lod0_detail / (2 * lod) };
|
||||
status.dirty = true;
|
||||
this->generator->push_task({ { position.x, position.z }, { this->size, this->size } }, status.mesh, base_detail > 1 ? base_detail : 1, callable_mp(this, &self_type::lod_generated).bind(lod));
|
||||
lod++;
|
||||
status.flag = MESH_DIRTY;
|
||||
}
|
||||
generate_lod(this->meshes.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void TerrainChunk::lod_generated(size_t lod) {
|
||||
this->meshes.set(lod, { this->meshes[lod].mesh, false });
|
||||
this->meshes.set(lod, { this->meshes[lod].mesh, MESH_LOADED });
|
||||
}
|
||||
|
||||
void TerrainChunk::process_lod() {
|
||||
size_t result{ (size_t)this->meshes.size() };
|
||||
if (is_ready() && this->meshes.size() > 0) {
|
||||
Vector3 position{ get_global_position() };
|
||||
position.y = 0;
|
||||
Vector3 camera{ get_viewport()->get_camera_3d()->get_global_position() };
|
||||
float distance{ (position - camera).length() - this->size / 2.f };
|
||||
camera.y = 0;
|
||||
float distance{ (position - camera).length() - this->size };
|
||||
distance = distance > 0.f ? distance : 0.f;
|
||||
size_t lod{ size_t(Math::floor(distance / (this->lod_end_distance / this->meshes.size()))) };
|
||||
size_t lod{ size_t(Math::floor(distance / ((this->max_lod_distance * this->size) / this->meshes.size()))) };
|
||||
result = lod < this->meshes.size() ? lod : (this->meshes.size() - 1);
|
||||
while (this->meshes[result].dirty && result < (this->meshes.size() - 1)) {
|
||||
if (this->meshes[result].flag == MESH_DIRTY) {
|
||||
generate_lod(result);
|
||||
}
|
||||
while (this->meshes[result].flag != MESH_LOADED && result < (this->meshes.size() - 1)) {
|
||||
result++;
|
||||
}
|
||||
if (this->meshes[result].mesh != this->get_mesh()) {
|
||||
|
|
|
|||
|
|
@ -6,11 +6,17 @@ class TerrainMeshGenerator;
|
|||
|
||||
class TerrainChunk : public MeshInstance3D {
|
||||
GDCLASS(TerrainChunk, MeshInstance3D);
|
||||
enum MeshStatusFlag {
|
||||
MESH_DIRTY,
|
||||
MESH_DISPATCHED,
|
||||
MESH_LOADED
|
||||
};
|
||||
struct MeshStatus {
|
||||
Ref<ArrayMesh> mesh;
|
||||
bool dirty;
|
||||
MeshStatusFlag flag;
|
||||
};
|
||||
static void _bind_methods();
|
||||
void generate_lod(size_t lod);
|
||||
void ready();
|
||||
void on_terrain_changed();
|
||||
void lod_generated(size_t lod);
|
||||
|
|
@ -27,10 +33,10 @@ public:
|
|||
|
||||
private:
|
||||
Node *collisions{ nullptr };
|
||||
size_t collisions_lod{ 0 };
|
||||
size_t lod_count{ 3 };
|
||||
Vector<MeshStatus> meshes{};
|
||||
int lod0_detail{ 200 };
|
||||
float lod_end_distance{ 600 };
|
||||
float max_lod_distance{ 6 };
|
||||
float size{ 200 };
|
||||
TerrainMeshGenerator *generator{ nullptr };
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue