Move both meshing and loading sheduling to LodOctree polling

This commit is contained in:
Marc Gilleron 2019-05-10 18:56:48 +01:00
parent 29298958e7
commit a521501add
4 changed files with 40 additions and 72 deletions

View File

@ -38,6 +38,10 @@ public:
void set_visible(bool visible);
bool is_visible() const;
inline bool is_mesh_update_scheduled() {
return _mesh_state == MESH_UPDATE_NOT_SENT || _mesh_state == MESH_UPDATE_SENT;
}
private:
VoxelBlock();

View File

@ -311,7 +311,7 @@ Vector3 VoxelLodTerrain::get_viewer_pos() const {
return Vector3();
}
void VoxelLodTerrain::load_block_and_neighbors(const Vector3i &p_bpos, unsigned int lod_index) {
void VoxelLodTerrain::try_schedule_loading_with_neighbors(const Vector3i &p_bpos, unsigned int lod_index) {
CRASH_COND(lod_index >= get_lod_count());
Lod &lod = _lods[lod_index];
@ -338,6 +338,34 @@ void VoxelLodTerrain::load_block_and_neighbors(const Vector3i &p_bpos, unsigned
}
}
bool VoxelLodTerrain::check_block_loaded_and_updated(const Vector3i &p_bpos, unsigned int lod_index) {
CRASH_COND(lod_index >= get_lod_count());
Lod &lod = _lods[lod_index];
VoxelBlock *block = lod.map->get_block(p_bpos);
if (block == nullptr) {
try_schedule_loading_with_neighbors(p_bpos, lod_index);
return false;
}
if (!block->has_been_meshed()) {
if (!block->is_mesh_update_scheduled()) {
if (lod.map->is_block_surrounded(block->pos)) {
lod.blocks_pending_update.push_back(block->pos);
block->set_mesh_state(VoxelBlock::MESH_UPDATE_NOT_SENT);
} else {
try_schedule_loading_with_neighbors(p_bpos, lod_index);
}
}
return false;
}
return true;
}
static void remove_positions_outside_box(
std::vector<Vector3i> &positions,
Rect3i box,
@ -430,32 +458,16 @@ void VoxelLodTerrain::_process() {
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];
bool can = true;
// 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 = LodOctree<bool>::get_child_position(node->position, i);
VoxelBlock *block = lod.map->get_block(child_pos);
if (block == nullptr) {
can = false;
self->load_block_and_neighbors(child_pos, child_lod_index);
} else if (!block->has_been_meshed()) {
// TODO There is a case where a whole region of map cannot load,
// because we end here everytime instead of the above.
can = false;
}
can &= self->check_block_loaded_and_updated(child_pos, child_lod_index);
}
if (!can) {
++blocked_count;
}
return can;
}
@ -464,6 +476,7 @@ void VoxelLodTerrain::_process() {
Vector3i bpos = node->position;
VoxelBlock *block = lod.map->get_block(bpos);
CRASH_COND(block == nullptr);
CRASH_COND(!block->has_been_meshed()); // Never show a block that hasn't been meshed
block->set_visible(true);
return true;
}
@ -475,24 +488,11 @@ void VoxelLodTerrain::_process() {
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];
const Vector3i &bpos = node->position;
VoxelBlock *block = lod.map->get_block(bpos);
bool can = true;
if (block == nullptr) {
can = false;
self->load_block_and_neighbors(bpos, lod_index);
} else if (!block->has_been_meshed()) {
can = false;
}
bool can = self->check_block_loaded_and_updated(bpos, lod_index);
if (!can) {
++blocked_count;
}
return can;
}
@ -580,48 +580,10 @@ void VoxelLodTerrain::_process() {
}
// Store buffer
bool check_neighbors = !lod.map->has_block(eo.block_position);
VoxelBlock *block = lod.map->set_block_buffer(eo.block_position, eo.voxels);
//print_line(String("Adding block {0} at lod {1}").format(varray(eo.block_position.to_vec3(), eo.lod)));
// The block will be made visible only by LodOctree
// The block will be made visible and meshed only by LodOctree
block->set_visible(false);
// if the block is surrounded or any of its neighbors becomes surrounded, and are marked to mesh,
// it should be added to meshing requests
if (check_neighbors) {
// The block was not there before, so its Moore neighbors may be surrounded now.
Vector3i ndir;
for (ndir.z = -1; ndir.z < 2; ++ndir.z) {
for (ndir.x = -1; ndir.x < 2; ++ndir.x) {
for (ndir.y = -1; ndir.y < 2; ++ndir.y) {
Vector3i npos = eo.block_position + ndir;
VoxelBlock *nblock = lod.map->get_block(npos);
if (nblock == nullptr) {
continue;
}
if (lod.map->is_block_surrounded(npos)) {
if (nblock->get_mesh_state() == VoxelBlock::MESH_UPDATE_NOT_SENT) {
// Assuming it is scheduled to be updated already.
// In case of BLOCK_UPDATE_SENT, we'll have to resend it.
continue;
}
nblock->set_mesh_state(VoxelBlock::MESH_UPDATE_NOT_SENT);
lod.blocks_pending_update.push_back(npos);
}
}
}
}
} else {
// Only update the block, neighbors will probably follow if needed
block->set_mesh_state(VoxelBlock::MESH_UPDATE_NOT_SENT);
lod.blocks_pending_update.push_back(eo.block_position);
}
}
}

View File

@ -72,7 +72,8 @@ private:
void immerge_block(Vector3i block_pos, unsigned int lod_index);
void reset_updater();
Vector3 get_viewer_pos() const;
void load_block_and_neighbors(const Vector3i &p_bpos, unsigned int lod_index);
void try_schedule_loading_with_neighbors(const Vector3i &p_bpos, unsigned int lod_index);
bool check_block_loaded_and_updated(const Vector3i &p_bpos, unsigned int lod_index);
template <typename A>
void for_all_blocks(A &action) {

View File

@ -160,6 +160,7 @@ bool VoxelMap::has_block(Vector3i pos) const {
}
bool VoxelMap::is_block_surrounded(Vector3i pos) const {
// TODO If that check proves to be too expensive with all blocks we deal with, cache it in VoxelBlocks
for (unsigned int i = 0; i < Cube::MOORE_NEIGHBORING_3D_COUNT; ++i) {
Vector3i bpos = pos + Cube::g_moore_neighboring_3d[i];
if (!has_block(bpos)) {