Don't subdivide or unsubdivide if meshes aren't ready

This commit is contained in:
Marc Gilleron 2019-05-04 16:29:52 +01:00
parent 9bab6c04d1
commit 295374b99f
3 changed files with 58 additions and 16 deletions

View File

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

View File

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

View File

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