Skip to content

Commit

Permalink
First WIP at paging LOD
Browse files Browse the repository at this point in the history
  • Loading branch information
Zylann committed Aug 29, 2019
1 parent db398a9 commit eb01f99
Show file tree
Hide file tree
Showing 8 changed files with 456 additions and 89 deletions.
54 changes: 53 additions & 1 deletion math/rect3i.h
Expand Up @@ -60,7 +60,7 @@ class Rect3i {
return String("(o:{0}, s:{1})").format(varray(pos.to_vec3(), size.to_vec3()));
}

bool intersects(Rect3i other) {
bool intersects(Rect3i other) const {
if (pos.x > other.pos.x + other.size.x)
return false;
if (pos.y > other.pos.y + other.size.y)
Expand All @@ -75,6 +75,58 @@ class Rect3i {
return false;
return true;
}

struct NoAction {
inline void operator()(const Vector3i pos) {}
};

template <typename A>
inline void for_each_cell(A &a) const {
Vector3i max = pos + size;
Vector3i p;
for (p.z = pos.z; p.z < max.z; ++p.z) {
for (p.y = pos.y; p.y < max.y; ++p.y) {
for (p.x = pos.x; p.x < max.x; ++p.x) {
a(p);
}
}
}
}

template <typename A, typename B>
static void check_enters_and_exits(const Rect3i &old_box, const Rect3i &new_box, A &exit_action, B &enter_action) {

if (old_box.intersects(new_box)) {

Rect3i bounds = Rect3i::get_bounding_box(old_box, new_box);
Vector3i max = bounds.pos + bounds.size;

// TODO There is a better way by checking all the possible cases

Vector3i pos;
for (pos.z = bounds.pos.z; pos.z < max.z; ++pos.z) {
for (pos.y = bounds.pos.y; pos.y < max.y; ++pos.y) {
for (pos.x = bounds.pos.x; pos.x < max.x; ++pos.x) {

bool old_contains = old_box.contains(pos);
bool new_contains = new_box.contains(pos);

if (old_contains && !new_contains) {
exit_action(pos);

} else if (!old_contains && new_contains) {
enter_action(pos);
}
}
}
}

} else {

old_box.for_each_cell(exit_action);
new_box.for_each_cell(enter_action);
}
}
};

inline bool operator!=(const Rect3i &a, const Rect3i &b) {
Expand Down
9 changes: 8 additions & 1 deletion register_types.cpp
Expand Up @@ -48,8 +48,15 @@ void register_voxel_types() {
ClassDB::register_class<VoxelMesherBlocky>();
ClassDB::register_class<VoxelMesherTransvoxel>();
ClassDB::register_class<VoxelMesherDMC>();

#ifdef TOOLS_ENABLED
VoxelDebug::create_debug_box_mesh();
#endif
}

void unregister_voxel_types() {
// lol

#ifdef TOOLS_ENABLED
VoxelDebug::free_debug_box_mesh();
#endif
}
4 changes: 2 additions & 2 deletions terrain/block_thread_manager.h
Expand Up @@ -29,7 +29,7 @@ class VoxelBlockThreadManager {
// Specialization must be copyable
struct InputBlock {
InputBlockData_T data;
Vector3i position; // In LOD0 block coordinates
Vector3i position; // In LOD-relative block coordinates
uint8_t lod = 0;
bool can_be_discarded = true; // If false, will always be processed, even if the thread is told to exit
float sort_heuristic = 0;
Expand All @@ -38,7 +38,7 @@ class VoxelBlockThreadManager {
// Specialization must be copyable
struct OutputBlock {
OutputBlockData_T data;
Vector3i position; // In LOD0 block coordinates
Vector3i position; // In LOD-relative block coordinates
unsigned int lod = 0;
// True if the block was actually dropped.
// Ideally the requester will agree that it doesn't need that block anymore,
Expand Down
30 changes: 25 additions & 5 deletions terrain/lod_octree.h
Expand Up @@ -96,7 +96,19 @@ class LodOctree {

template <typename A, typename B>
void update(Vector3 view_pos, A &create_action, B &destroy_action) {
update(&_root, _max_depth, view_pos, create_action, destroy_action);

if (_root.block || _root.has_children()) {
update(&_root, _max_depth, view_pos, create_action, destroy_action);

} else {
// Treat the root in a slightly different way the first time.
// `can_do` takes child lod into account, but here it's like it is child of nothing.
// Careful when handling that case
if (create_action.can_do_root(_max_depth)) {
//print_line(String::num_int64((int64_t)this, 16) + String("Create LOD {0} pos {1} (root)").format(varray(_max_depth, _root.position.to_vec3())));
_root.block = create_action(&_root, _max_depth);
}
}
}

template <typename A>
Expand Down Expand Up @@ -134,13 +146,14 @@ class LodOctree {
if (!node->has_children()) {

// 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)) {
if (lod > 0 && world_center.distance_to(view_pos) < split_distance && create_action.can_do_children(node, lod - 1)) {
// Split
for (int i = 0; i < 8; ++i) {

Node *child = _pool.create();

child->position = get_child_position(node->position, i);
//print_line(String::num_int64((int64_t)this, 16) + String("Create LOD {0} pos {1} (subdiv)").format(varray(lod - 1, child->position.to_vec3())));
child->block = create_action(child, lod - 1);

node->children[i] = child;
Expand All @@ -150,35 +163,40 @@ class LodOctree {
}

if (node->block) {
//print_line(String::num_int64((int64_t)this, 16) + String("Destroy LOD {0} pos {1}").format(varray(lod, node->position.to_vec3())));
destroy_action(node, lod);
node->block = T();
}
}

} else {

bool no_split_child = true;
bool has_split_child = false;

for (int i = 0; i < 8; ++i) {
Node *child = node->children[i];
update(child, lod - 1, view_pos, create_action, destroy_action);
no_split_child |= child->has_children();
has_split_child |= child->has_children();
}

if (no_split_child && world_center.distance_to(view_pos) > split_distance && destroy_action.can_do(node, lod)) {
if (!has_split_child && world_center.distance_to(view_pos) > split_distance && destroy_action.can_do(node, lod)) {
// Join
if (node->has_children()) {

for (int i = 0; i < 8; ++i) {
Node *child = node->children[i];
//print_line(String::num_int64((int64_t)this, 16) + String("Destroy LOD {0} pos {1} (join)").format(varray(lod - 1, child->position.to_vec3())));
destroy_action(child, lod - 1);
child->block = T();
_pool.recycle(child);
}

node->children[0] = nullptr;

// If this is true, means the parent wasn't properly split.
// When subdividing a node, that node's block must be destroyed as it is replaced by its children.
CRASH_COND(node->block);

node->block = create_action(node, lod);
}
}
Expand All @@ -201,6 +219,7 @@ class LodOctree {
} else {
if (node->block) {
destroy_action(node, lod);
//print_line(String::num_int64((int64_t)this, 16) + String("Cleanup LOD {0} pos {1}").format(varray(lod, node->position.to_vec3())));
node->block = T();
}
}
Expand All @@ -210,6 +229,7 @@ class LodOctree {
int _max_depth = 0;
float _base_size = 16;
float _split_scale = 2.0;
// TODO May be worth making this pool external for sharing purpose
ObjectPool<Node> _pool;
};

Expand Down

0 comments on commit eb01f99

Please sign in to comment.