Better fix for VoxelLodTerrain task drop

master
Marc Gilleron 2020-10-20 23:58:55 +01:00
parent 54eb228444
commit 2dfcc76600
4 changed files with 53 additions and 28 deletions

View File

@ -140,9 +140,10 @@ int VoxelServer::get_priority(const PriorityDependency &dep, uint8_t lod, float
return priority;
}
uint32_t VoxelServer::add_volume(ReceptionBuffers *buffers) {
uint32_t VoxelServer::add_volume(ReceptionBuffers *buffers, VolumeType type) {
CRASH_COND(buffers == nullptr);
Volume volume;
volume.type = type;
volume.reception_buffers = buffers;
volume.meshing_dependency = gd_make_shared<MeshingDependency>();
return _world.volumes.create(volume);
@ -184,9 +185,9 @@ void VoxelServer::set_volume_voxel_library(uint32_t volume_id, Ref<VoxelLibrary>
volume.meshing_dependency->library = volume.voxel_library;
}
void VoxelServer::set_volume_cancellable_requests(uint32_t volume_id, bool cancellable) {
void VoxelServer::set_volume_octree_split_scale(uint32_t volume_id, float split_scale) {
Volume &volume = _world.volumes.get(volume_id);
volume.cancellable_requests = cancellable;
volume.octree_split_scale = split_scale;
}
void VoxelServer::invalidate_volume_mesh_requests(uint32_t volume_id) {
@ -207,7 +208,27 @@ void VoxelServer::init_priority_dependency(
const float block_radius = (volume.block_size << lod) / 2;
dep.shared = _world.shared_priority_dependency;
dep.world_position = volume.transform.xform(voxel_pos.to_vec3());
dep.radius = volume.transform.basis.xform(Vector3(block_radius, block_radius, block_radius)).length();
const float transformed_block_radius =
volume.transform.basis.xform(Vector3(block_radius, block_radius, block_radius)).length();
switch (volume.type) {
case VOLUME_SPARSE_GRID:
// Distance beyond which no field of view can overlap the block
dep.drop_distance_squared =
squared(_world.shared_priority_dependency->highest_view_distance + transformed_block_radius);
break;
case VOLUME_SPARSE_OCTREE:
// Distance beyond which it is safe to drop a block without risking to block LOD subdivision.
// This does not depend on viewer's view distance, but on LOD precision instead.
dep.drop_distance_squared = squared(2.f * transformed_block_radius *
get_octree_lod_block_region_extent(volume.octree_split_scale));
break;
default:
CRASH_NOW_MSG("Unexpected type");
break;
}
}
void VoxelServer::request_block_mesh(uint32_t volume_id, BlockMeshInput &input) {
@ -221,7 +242,6 @@ void VoxelServer::request_block_mesh(uint32_t volume_id, BlockMeshInput &input)
r->blocks = input.blocks;
r->position = input.position;
r->lod = input.lod;
r->cancellable = volume.cancellable_requests;
r->smooth_enabled = volume.stream->get_used_channels_mask() & (1 << VoxelBuffer::CHANNEL_SDF);
r->blocky_enabled = volume.voxel_library.is_valid() &&
@ -246,7 +266,6 @@ void VoxelServer::request_block_load(uint32_t volume_id, Vector3i block_pos, int
r.lod = lod;
r.type = BlockDataRequest::TYPE_LOAD;
r.block_size = volume.block_size;
r.cancellable = volume.cancellable_requests;
r.stream_dependency = volume.stream_dependency;
@ -564,10 +583,7 @@ int VoxelServer::BlockDataRequest::get_priority() {
}
float closest_viewer_distance_sq;
const int p = VoxelServer::get_priority(priority_dependency, lod, &closest_viewer_distance_sq);
if (cancellable) {
const float closest_viewer_distance = Math::sqrt(closest_viewer_distance_sq);
too_far = closest_viewer_distance > priority_dependency.radius + priority_dependency.shared->highest_view_distance;
}
too_far = closest_viewer_distance_sq > priority_dependency.drop_distance_squared;
return p;
}
@ -662,10 +678,7 @@ void VoxelServer::BlockMeshRequest::run(VoxelTaskContext ctx) {
int VoxelServer::BlockMeshRequest::get_priority() {
float closest_viewer_distance_sq;
const int p = VoxelServer::get_priority(priority_dependency, lod, &closest_viewer_distance_sq);
if (cancellable) {
const float closest_viewer_distance = Math::sqrt(closest_viewer_distance_sq);
too_far = closest_viewer_distance > priority_dependency.radius + priority_dependency.shared->highest_view_distance;
}
too_far = closest_viewer_distance_sq > priority_dependency.drop_distance_squared;
return p;
}

View File

@ -66,6 +66,11 @@ public:
bool is_default = false;
};
enum VolumeType {
VOLUME_SPARSE_GRID,
VOLUME_SPARSE_OCTREE
};
static VoxelServer *get_singleton();
static void create_singleton();
static void destroy_singleton();
@ -73,18 +78,20 @@ public:
VoxelServer();
~VoxelServer();
uint32_t add_volume(ReceptionBuffers *buffers);
// TODO Rename functions to C convention
uint32_t add_volume(ReceptionBuffers *buffers, VolumeType type);
void set_volume_transform(uint32_t volume_id, Transform t);
void set_volume_block_size(uint32_t volume_id, uint32_t block_size);
void set_volume_stream(uint32_t volume_id, Ref<VoxelStream> stream);
void set_volume_voxel_library(uint32_t volume_id, Ref<VoxelLibrary> library);
void set_volume_cancellable_requests(uint32_t volume_id, bool cancellable);
void set_volume_octree_split_scale(uint32_t volume_id, float split_scale);
void invalidate_volume_mesh_requests(uint32_t volume_id);
void request_block_mesh(uint32_t volume_id, BlockMeshInput &input);
void request_block_load(uint32_t volume_id, Vector3i block_pos, int lod);
void request_block_save(uint32_t volume_id, Ref<VoxelBuffer> voxels, Vector3i block_pos, int lod);
void remove_volume(uint32_t volume_id);
// TODO Rename functions to C convention
uint32_t add_viewer();
void remove_viewer(uint32_t viewer_id);
void set_viewer_position(uint32_t viewer_id, Vector3 position);
@ -109,6 +116,13 @@ public:
void process();
void wait_and_clear_all_tasks(bool warn);
static inline int get_octree_lod_block_region_extent(float split_scale) {
// This is a bounding radius of blocks around a viewer within which we may load them.
// It depends on the LOD split scale, which tells how close to a block we need to be for it to subdivide.
// Each LOD is fractal so that value is the same for each of them, multiplied by 2^lod.
return static_cast<int>(split_scale) * 2 + 2;
}
private:
Dictionary _b_get_stats();
@ -139,15 +153,15 @@ private:
};
struct Volume {
VolumeType type;
ReceptionBuffers *reception_buffers = nullptr;
Transform transform;
Ref<VoxelStream> stream;
Ref<VoxelLibrary> voxel_library;
uint32_t block_size = 16;
float octree_split_scale = 0;
std::shared_ptr<StreamingDependency> stream_dependency;
std::shared_ptr<MeshingDependency> meshing_dependency;
// TODO Workaround for VoxelLodTerrain, which doesnt support this well atm
bool cancellable_requests = true;
};
struct PriorityDependencyShared {
@ -170,7 +184,8 @@ private:
struct PriorityDependency {
std::shared_ptr<PriorityDependencyShared> shared;
Vector3 world_position; // TODO Won't update while in queue. Can it be bad?
float radius;
// If the closest viewer is further away than this distance, the request can be cancelled as not worth it
float drop_distance_squared;
};
void init_priority_dependency(PriorityDependency &dep, Vector3i block_position, uint8_t lod, const Volume &volume);
@ -195,7 +210,6 @@ private:
uint8_t type;
bool has_run = false;
bool too_far = false;
bool cancellable = true;
PriorityDependency priority_dependency;
std::shared_ptr<StreamingDependency> stream_dependency;
// TODO Find a way to separate save, it doesnt need sorting
@ -215,7 +229,6 @@ private:
bool blocky_enabled;
bool has_run = false;
bool too_far = false;
bool cancellable = true;
PriorityDependency priority_dependency;
std::shared_ptr<MeshingDependency> meshing_dependency;
VoxelMesher::Output blocky_surfaces_output;

View File

@ -56,8 +56,8 @@ VoxelLodTerrain::VoxelLodTerrain() {
PRINT_VERBOSE("Construct VoxelLodTerrain");
_volume_id = VoxelServer::get_singleton()->add_volume(&_reception_buffers);
VoxelServer::get_singleton()->set_volume_cancellable_requests(_volume_id, false);
_volume_id = VoxelServer::get_singleton()->add_volume(&_reception_buffers, VoxelServer::VOLUME_SPARSE_OCTREE);
VoxelServer::get_singleton()->set_volume_octree_split_scale(_volume_id, get_lod_split_scale());
_lods[0].map.instance();
@ -310,6 +310,8 @@ void VoxelLodTerrain::set_lod_split_scale(float p_lod_split_scale) {
// Because `set_split_scale` may clamp it...
_lod_split_scale = item.octree.get_split_scale();
}
VoxelServer::get_singleton()->set_volume_octree_split_scale(_volume_id, get_lod_split_scale());
}
float VoxelLodTerrain::get_lod_split_scale() const {
@ -398,10 +400,7 @@ NodePath VoxelLodTerrain::get_viewer_path() const {
}
int VoxelLodTerrain::get_block_region_extent() const {
// This is the radius of blocks around the viewer in which we may load them.
// It depends on the LOD split scale, which tells how close to a block we need to be for it to subdivide.
// Each LOD is fractal so that value is the same for each of them.
return static_cast<int>(_lod_split_scale) * 2 + 2;
return VoxelServer::get_octree_lod_block_region_extent(_lod_split_scale);
}
Vector3 VoxelLodTerrain::voxel_to_block_position(Vector3 vpos, int lod_index) const {

View File

@ -24,7 +24,7 @@ VoxelTerrain::VoxelTerrain() {
// Infinite by default
_bounds_in_voxels = Rect3i::from_center_extents(Vector3i(0), Vector3i(MAX_EXTENT));
_volume_id = VoxelServer::get_singleton()->add_volume(&_reception_buffers);
_volume_id = VoxelServer::get_singleton()->add_volume(&_reception_buffers, VoxelServer::VOLUME_SPARSE_GRID);
_map.instance();