mirror of
https://github.com/Relintai/godot_voxel.git
synced 2025-02-14 12:10:07 +01:00
Don't subdivide or unsubdivide if meshes aren't ready
This commit is contained in:
parent
9bab6c04d1
commit
295374b99f
@ -126,7 +126,8 @@ private:
|
||||
|
||||
if (!node->has_children()) {
|
||||
|
||||
if (lod > 0 && world_center.distance_to(view_pos) < split_distance) {
|
||||
// If it's not the last LOD, if close enough and custom conditions get fulfilled
|
||||
if (lod > 0 && world_center.distance_to(view_pos) < split_distance && create_action.can_do(node, lod)) {
|
||||
// Split
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
|
||||
@ -160,7 +161,7 @@ private:
|
||||
no_split_child |= child->has_children();
|
||||
}
|
||||
|
||||
if (no_split_child && world_center.distance_to(view_pos) > split_distance) {
|
||||
if (no_split_child && world_center.distance_to(view_pos) > split_distance && destroy_action.can_do(node, lod)) {
|
||||
// Join
|
||||
if (node->has_children()) {
|
||||
|
||||
|
@ -13,6 +13,10 @@ public:
|
||||
Vector3i pos; // TODO Rename position
|
||||
unsigned int lod_index = 0;
|
||||
|
||||
// The mesh might be null, but we don't know if it's actually empty or if it's loading.
|
||||
// This boolean tells if we attempted to mesh this block at least once.
|
||||
bool has_been_meshed = false;
|
||||
|
||||
static VoxelBlock *create(Vector3i bpos, Ref<VoxelBuffer> buffer, unsigned int size, unsigned int p_lod_index);
|
||||
|
||||
void set_mesh(Ref<Mesh> mesh, Ref<World> world);
|
||||
|
@ -12,8 +12,8 @@ VoxelLodTerrain::VoxelLodTerrain() {
|
||||
|
||||
_lods[0].map.instance();
|
||||
|
||||
set_lod_count(4);
|
||||
set_lod_split_scale(2);
|
||||
set_lod_count(8);
|
||||
set_lod_split_scale(3);
|
||||
|
||||
reset_updater();
|
||||
}
|
||||
@ -660,6 +660,7 @@ void VoxelLodTerrain::_process() {
|
||||
|
||||
block->set_mesh(mesh, world);
|
||||
block->set_visible(lod.blocks_in_meshing_area.has(ob.position));
|
||||
block->has_been_meshed = true;
|
||||
}
|
||||
|
||||
shift_up(_blocks_pending_main_thread_update, queue_index);
|
||||
@ -667,23 +668,59 @@ void VoxelLodTerrain::_process() {
|
||||
|
||||
// Find out which blocks need to be shown
|
||||
{
|
||||
struct ShowAction {
|
||||
struct SubdivideAction {
|
||||
VoxelLodTerrain *self;
|
||||
bool operator()(LodOctree<bool>::Node *node, int lod_index) {
|
||||
|
||||
bool can_do(LodOctree<bool>::Node *node, unsigned int lod_index) {
|
||||
CRASH_COND(lod_index == 0);
|
||||
|
||||
unsigned int child_lod_index = lod_index - 1;
|
||||
Lod &lod = self->_lods[child_lod_index];
|
||||
|
||||
// Can only subdivide if higher detail meshes are ready to be shown, otherwise it will produce holes
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
|
||||
Vector3i child_pos = node->position;
|
||||
|
||||
child_pos.x = node->position.x * 2 + OctreeTables::g_octant_position[i][0];
|
||||
child_pos.y = node->position.y * 2 + OctreeTables::g_octant_position[i][1];
|
||||
child_pos.z = node->position.z * 2 + OctreeTables::g_octant_position[i][2];
|
||||
|
||||
VoxelBlock *block = lod.map->get_block(child_pos);
|
||||
if (block == nullptr || !block->has_been_meshed) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator()(LodOctree<bool>::Node *node, unsigned int lod_index) {
|
||||
Lod &lod = self->_lods[lod_index];
|
||||
Vector3i bpos = node->position;
|
||||
lod.blocks_in_meshing_area.insert(bpos);
|
||||
VoxelBlock *block = lod.map->get_block(bpos);
|
||||
if (block != nullptr) {
|
||||
block->set_visible(true);
|
||||
}
|
||||
CRASH_COND(block == nullptr);
|
||||
block->set_visible(true);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct HideAction {
|
||||
struct UnsubdivideAction {
|
||||
VoxelLodTerrain *self;
|
||||
void operator()(LodOctree<bool>::Node *node, int lod_index) {
|
||||
|
||||
bool can_do(LodOctree<bool>::Node *node, unsigned int lod_index) {
|
||||
// Can only unsubdivide if the parent mesh is ready
|
||||
Lod &lod = self->_lods[lod_index];
|
||||
VoxelBlock *block = lod.map->get_block(node->position);
|
||||
if (block == nullptr) {
|
||||
// Ok, that block got unloaded? Might happen if you teleport away
|
||||
return true;
|
||||
} else {
|
||||
return block->has_been_meshed;
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(LodOctree<bool>::Node *node, unsigned int lod_index) {
|
||||
Lod &lod = self->_lods[lod_index];
|
||||
Vector3i bpos = node->position;
|
||||
lod.blocks_in_meshing_area.erase(bpos);
|
||||
@ -694,13 +731,13 @@ void VoxelLodTerrain::_process() {
|
||||
}
|
||||
};
|
||||
|
||||
ShowAction show_action;
|
||||
show_action.self = this;
|
||||
SubdivideAction subdivide_action;
|
||||
subdivide_action.self = this;
|
||||
|
||||
HideAction hide_action;
|
||||
hide_action.self = this;
|
||||
UnsubdivideAction unsubdivide_action;
|
||||
unsubdivide_action.self = this;
|
||||
|
||||
_lod_octree.update(viewer_pos, show_action, hide_action);
|
||||
_lod_octree.update(viewer_pos, subdivide_action, unsubdivide_action);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user