Instancing persistence is now opt-in

master
Marc Gilleron 2021-02-08 22:20:18 +00:00
parent 7f47b07e0c
commit c6fdbb675b
3 changed files with 158 additions and 109 deletions

View File

@ -175,6 +175,15 @@ void VoxelInstanceGenerator::generate_transforms(
out_transforms.push_back(t); out_transforms.push_back(t);
} }
// TODO Investigate if this helps (won't help with authored terrain)
// if (graph_generator.is_valid()) {
// for (size_t i = 0; i < _transform_cache.size(); ++i) {
// Transform &t = _transform_cache[i];
// const Vector3 up = t.get_basis().get_axis(Vector3::AXIS_Y);
// t.origin = graph_generator->approximate_surface(t.origin, up * 0.5f);
// }
// }
} }
void VoxelInstanceGenerator::set_density(float density) { void VoxelInstanceGenerator::set_density(float density) {

View File

@ -205,20 +205,21 @@ VoxelInstancer::UpMode VoxelInstancer::get_up_mode() const {
return _up_mode; return _up_mode;
} }
int VoxelInstancer::add_layer(int lod_index) { int VoxelInstancer::generate_persistent_id() const {
// Find unused ID
int id = 0; int id = 0;
for (size_t i = 0; i < _layers.size(); ++i) { for (size_t i = 0; i < _layers.size(); ++i) {
const Layer *layer = _layers[i]; const Layer *layer = _layers[i];
if (layer != nullptr) { if (layer != nullptr) {
id = max(layer->id + 1, id); id = max(layer->persistent_id + 1, id);
break; break;
} }
} }
// Should not happen // Should not happen
ERR_FAIL_COND_V(id > Layer::MAX_ID, -1); ERR_FAIL_COND_V(id > Layer::MAX_ID, -1);
return id;
}
int VoxelInstancer::add_layer(int lod_index) {
int layer_index = -1; int layer_index = -1;
for (size_t i = 0; i < _layers.size(); ++i) { for (size_t i = 0; i < _layers.size(); ++i) {
if (_layers[i] == nullptr) { if (_layers[i] == nullptr) {
@ -233,7 +234,6 @@ int VoxelInstancer::add_layer(int lod_index) {
Layer *layer = memnew(Layer); Layer *layer = memnew(Layer);
layer->lod_index = lod_index; layer->lod_index = lod_index;
layer->id = id;
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
// Put a default generator // Put a default generator
@ -256,6 +256,21 @@ void VoxelInstancer::set_layer_generator(int layer_index, Ref<VoxelInstanceGener
layer->generator = generator; layer->generator = generator;
} }
void VoxelInstancer::set_layer_persistent(int layer_index, bool persistent) {
ERR_FAIL_INDEX(layer_index, _layers.size());
Layer *layer = _layers[layer_index];
ERR_FAIL_COND(layer == nullptr);
if (persistent) {
layer->persistent = true;
if (layer->persistent_id < 0 || find_layer_by_persistent_id(layer->persistent_id) != -1) {
layer->persistent_id = generate_persistent_id();
}
} else {
layer->persistent = false;
}
}
void VoxelInstancer::set_layer_mesh(int layer_index, Ref<Mesh> mesh) { void VoxelInstancer::set_layer_mesh(int layer_index, Ref<Mesh> mesh) {
ERR_FAIL_INDEX(layer_index, _layers.size()); ERR_FAIL_INDEX(layer_index, _layers.size());
Layer *layer = _layers[layer_index]; Layer *layer = _layers[layer_index];
@ -434,16 +449,18 @@ void VoxelInstancer::on_block_enter(Vector3i grid_position, int lod_index, Array
Lod &lod = _lods[lod_index]; Lod &lod = _lods[lod_index];
auto it = lod.loaded_instances_data.find(grid_position); auto it = lod.loaded_instances_data.find(grid_position);
const VoxelInstanceBlockData *instances_data = nullptr;
if (it != lod.loaded_instances_data.end()) { if (it != lod.loaded_instances_data.end()) {
ERR_FAIL_COND(it->second == nullptr); instances_data = it->second.get();
create_loaded_blocks(*it->second, grid_position, lod_index); ERR_FAIL_COND(instances_data == nullptr);
// Data no longer needed in this form
lod.loaded_instances_data.erase(grid_position);
} else { // We could do this:
generate_block_on_each_layer(grid_position, lod_index, surface_arrays); // lod.loaded_instances_data.erase(grid_position);
// but we'd loose the information that this block was edited, so keeping it for now
} }
create_blocks(instances_data, grid_position, lod_index, surface_arrays);
} }
void VoxelInstancer::on_block_exit(Vector3i grid_position, int lod_index) { void VoxelInstancer::on_block_exit(Vector3i grid_position, int lod_index) {
@ -547,18 +564,29 @@ void VoxelInstancer::create_block_from_transforms(ArraySlice<const Transform> tr
layer->blocks.set(grid_position, block_index); layer->blocks.set(grid_position, block_index);
} }
int VoxelInstancer::find_layer_by_id(int id) const { int VoxelInstancer::find_layer_by_persistent_id(int id) const {
ERR_FAIL_COND_V(id < 0, -1);
for (size_t i = 0; i < _layers.size(); ++i) { for (size_t i = 0; i < _layers.size(); ++i) {
const Layer *layer = _layers[i]; const Layer *layer = _layers[i];
if (layer != nullptr && layer->id == id) { if (layer != nullptr && layer->persistent_id == id) {
return i; return i;
} }
} }
return -1; return -1;
} }
void VoxelInstancer::create_loaded_blocks(const VoxelInstanceBlockData &instances_data, Vector3i grid_position, static bool contains_layer_id(const VoxelInstanceBlockData &instances_data, int id) {
int lod_index) { for (auto it = instances_data.layers.begin(); it != instances_data.layers.end(); ++it) {
const VoxelInstanceBlockData::LayerData &layer = *it;
if (layer.id == id) {
return true;
}
}
return false;
}
void VoxelInstancer::create_blocks(const VoxelInstanceBlockData *instances_data_ptr, Vector3i grid_position,
int lod_index, Array surface_arrays) {
VOXEL_PROFILE_SCOPE(); VOXEL_PROFILE_SCOPE();
@ -572,10 +600,15 @@ void VoxelInstancer::create_loaded_blocks(const VoxelInstanceBlockData &instance
const Transform block_local_transform = Transform(Basis(), (grid_position * lod_block_size).to_vec3()); const Transform block_local_transform = Transform(Basis(), (grid_position * lod_block_size).to_vec3());
const Transform block_transform = parent_transform * block_local_transform; const Transform block_transform = parent_transform * block_local_transform;
// Load from data if any
if (instances_data_ptr != nullptr) {
VOXEL_PROFILE_SCOPE();
const VoxelInstanceBlockData &instances_data = *instances_data_ptr;
for (auto layer_it = instances_data.layers.begin(); layer_it != instances_data.layers.end(); ++layer_it) { for (auto layer_it = instances_data.layers.begin(); layer_it != instances_data.layers.end(); ++layer_it) {
const VoxelInstanceBlockData::LayerData &layer_data = *layer_it; const VoxelInstanceBlockData::LayerData &layer_data = *layer_it;
const int layer_index = find_layer_by_id(layer_data.id); const int layer_index = find_layer_by_persistent_id(layer_data.id);
if (layer_index == -1) { if (layer_index == -1) {
ERR_PRINT(String("Could not find associated layer ID {0} from loaded instances data") ERR_PRINT(String("Could not find associated layer ID {0} from loaded instances data")
.format(varray(layer_data.id))); .format(varray(layer_data.id)));
@ -585,47 +618,45 @@ void VoxelInstancer::create_loaded_blocks(const VoxelInstanceBlockData &instance
Layer *layer = _layers[layer_index]; Layer *layer = _layers[layer_index];
CRASH_COND(layer == nullptr); CRASH_COND(layer == nullptr);
const int *block_index_ptr = layer->blocks.getptr(grid_position); if (!layer->persistent) {
// That layer is no longer persistent so we'll have to ignore authored data...
WARN_PRINT(String("Layer index={0} received loaded data but is no longer persistent. "
"Loaded data will be ignored.")
.format(varray(layer_index)));
continue;
}
const int *block_index_ptr = layer->blocks.getptr(grid_position);
if (block_index_ptr != nullptr) { if (block_index_ptr != nullptr) {
// The block was already made? // The block was already made?
continue; continue;
} }
// TODO Don't create blocks if there are no transforms?
static_assert(sizeof(VoxelInstanceBlockData::InstanceData) == sizeof(Transform), static_assert(sizeof(VoxelInstanceBlockData::InstanceData) == sizeof(Transform),
"Assuming instance data only contains a transform for now"); "Assuming instance data only contains a transform for now");
ArraySlice<const Transform> transforms( ArraySlice<const Transform> transforms(
reinterpret_cast<const Transform *>(layer_data.instances.data()), layer_data.instances.size()); reinterpret_cast<const Transform *>(layer_data.instances.data()), layer_data.instances.size());
create_block_from_transforms(transforms, grid_position, layer, layer_index, world, block_transform); create_block_from_transforms(transforms, grid_position, layer, layer_index, world, block_transform);
} }
} }
// Generate other blocks
{
VOXEL_PROFILE_SCOPE();
void VoxelInstancer::generate_block_on_each_layer(Vector3i grid_position, int lod_index, Array surface_arrays) {
if (surface_arrays.size() == 0) { if (surface_arrays.size() == 0) {
return; return;
} }
PoolVector3Array vertices = surface_arrays[ArrayMesh::ARRAY_VERTEX]; PoolVector3Array vertices = surface_arrays[ArrayMesh::ARRAY_VERTEX];
if (vertices.size() == 0) { if (vertices.size() == 0) {
return; return;
} }
VOXEL_PROFILE_SCOPE();
PoolVector3Array normals = surface_arrays[ArrayMesh::ARRAY_NORMAL]; PoolVector3Array normals = surface_arrays[ArrayMesh::ARRAY_NORMAL];
ERR_FAIL_COND(normals.size() == 0);
//Ref<VoxelGeneratorGraph> graph_generator = _parent->get_stream();
Lod &lod = _lods[lod_index];
const Transform parent_transform = get_global_transform();
Ref<World> world_ref = get_world();
ERR_FAIL_COND(world_ref.is_null());
World *world = *world_ref;
const int lod_block_size = _parent->get_block_size() << lod_index;
const Transform block_local_transform = Transform(Basis(), (grid_position * lod_block_size).to_vec3());
const Transform block_transform = parent_transform * block_local_transform;
for (auto it = lod.layers.begin(); it != lod.layers.end(); ++it) { for (auto it = lod.layers.begin(); it != lod.layers.end(); ++it) {
const int layer_index = *it; const int layer_index = *it;
@ -638,12 +669,17 @@ void VoxelInstancer::generate_block_on_each_layer(Vector3i grid_position, int lo
} }
const int *block_index_ptr = layer->blocks.getptr(grid_position); const int *block_index_ptr = layer->blocks.getptr(grid_position);
if (block_index_ptr != nullptr) { if (block_index_ptr != nullptr) {
// The block was already made? // The block was already made?
continue; continue;
} }
if (layer->persistent && instances_data_ptr != nullptr &&
contains_layer_id(*instances_data_ptr, layer->persistent_id)) {
// Don't generate, it received modified data
continue;
}
_transform_cache.clear(); _transform_cache.clear();
layer->generator->generate_transforms( layer->generator->generate_transforms(
@ -659,18 +695,10 @@ void VoxelInstancer::generate_block_on_each_layer(Vector3i grid_position, int lo
continue; continue;
} }
// TODO Investigate if this helps (won't help with authored terrain)
// if (graph_generator.is_valid()) {
// for (size_t i = 0; i < _transform_cache.size(); ++i) {
// Transform &t = _transform_cache[i];
// const Vector3 up = t.get_basis().get_axis(Vector3::AXIS_Y);
// t.origin = graph_generator->approximate_surface(t.origin, up * 0.5f);
// }
// }
create_block_from_transforms(to_slice_const(_transform_cache), create_block_from_transforms(to_slice_const(_transform_cache),
grid_position, layer, layer_index, world, block_transform); grid_position, layer, layer_index, world, block_transform);
} }
}
} }
static inline int get_visible_instance_count(Ref<MultiMesh> mm) { static inline int get_visible_instance_count(Ref<MultiMesh> mm) {
@ -698,6 +726,11 @@ void VoxelInstancer::save_block(Vector3i grid_pos, int lod_index) const {
Layer *layer = _layers[layer_index]; Layer *layer = _layers[layer_index];
CRASH_COND(layer == nullptr); CRASH_COND(layer == nullptr);
if (!layer->persistent) {
continue;
}
ERR_FAIL_COND(layer->persistent_id < 0);
int *block_index_ptr = layer->blocks.getptr(grid_pos); int *block_index_ptr = layer->blocks.getptr(grid_pos);
if (block_index_ptr != nullptr) { if (block_index_ptr != nullptr) {
@ -716,8 +749,7 @@ void VoxelInstancer::save_block(Vector3i grid_pos, int lod_index) const {
const int instance_count = get_visible_instance_count(multimesh); const int instance_count = get_visible_instance_count(multimesh);
ERR_FAIL_COND(layer->id < 0); layer_data.id = layer->persistent_id;
layer_data.id = layer->id;
if (layer->generator.is_valid()) { if (layer->generator.is_valid()) {
layer_data.scale_min = layer->generator->get_min_scale(); layer_data.scale_min = layer->generator->get_min_scale();
@ -914,6 +946,9 @@ void VoxelInstancer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_layer_generator", "layer_index", "generator"), ClassDB::bind_method(D_METHOD("set_layer_generator", "layer_index", "generator"),
&VoxelInstancer::set_layer_generator); &VoxelInstancer::set_layer_generator);
ClassDB::bind_method(D_METHOD("set_layer_persistent", "layer_index", "persistent"),
&VoxelInstancer::set_layer_persistent);
ClassDB::bind_method(D_METHOD("set_layer_mesh", "layer_index", "mesh"), &VoxelInstancer::set_layer_mesh); ClassDB::bind_method(D_METHOD("set_layer_mesh", "layer_index", "mesh"), &VoxelInstancer::set_layer_mesh);
ClassDB::bind_method(D_METHOD("set_layer_mesh_material_override", "layer_index", "material"), ClassDB::bind_method(D_METHOD("set_layer_mesh_material_override", "layer_index", "material"),
&VoxelInstancer::set_layer_material_override); &VoxelInstancer::set_layer_material_override);

View File

@ -45,6 +45,7 @@ public:
int add_layer(int lod_index); int add_layer(int lod_index);
void set_layer_generator(int layer_index, Ref<VoxelInstanceGenerator> generator); void set_layer_generator(int layer_index, Ref<VoxelInstanceGenerator> generator);
void set_layer_persistent(int layer_index, bool persistent);
void set_layer_mesh(int layer_index, Ref<Mesh> mesh); void set_layer_mesh(int layer_index, Ref<Mesh> mesh);
void set_layer_material_override(int layer_index, Ref<Material> material); void set_layer_material_override(int layer_index, Ref<Material> material);
@ -85,11 +86,12 @@ private:
void clear_instances(); void clear_instances();
void update_visibility(); void update_visibility();
void save_block(Vector3i grid_pos, int lod_index) const; void save_block(Vector3i grid_pos, int lod_index) const;
void generate_block_on_each_layer(Vector3i grid_pos, int lod_index, Array surface_arrays);
int find_layer_by_id(int id) const; int find_layer_by_persistent_id(int id) const;
int generate_persistent_id() const;
void create_loaded_blocks(const VoxelInstanceBlockData &instances_data, Vector3i grid_position, int lod_index); void create_blocks(const VoxelInstanceBlockData *instances_data, Vector3i grid_position, int lod_index,
Array surface_arrays);
void create_block_from_transforms(ArraySlice<const Transform> transforms, void create_block_from_transforms(ArraySlice<const Transform> transforms,
Vector3i grid_position, Layer *layer, unsigned int layer_index, World *world, Vector3i grid_position, Layer *layer, unsigned int layer_index, World *world,
@ -114,11 +116,14 @@ private:
struct Layer { struct Layer {
static const int MAX_ID = 0xffff; static const int MAX_ID = 0xffff;
// This ID identifies the layer uniquely within the current volume, and within saved data. // This ID identifies the layer uniquely within saved data. Two layers cannot use the same ID.
// Note: layer indexes are used only for fast access, they are not persistent. // Note: layer indexes are used only for fast access, they are not persistent.
int id = -1; int persistent_id = -1;
// TODO Allow non-persistent layers? // If a layer is persistent, any change to its instances will be saved if the volume has a stream
// These won't need an ID, will not be saved, and will always re-generate. Also rename `id` to `persistent_id`. // supporting instances. It will also not generate on top of modified surfaces.
// If a layer is not persistent, changes won't get saved, and it will keep generating on all compliant
// surfaces.
bool persistent = false;
int lod_index = 0; int lod_index = 0;