Merge branch 'master' into instancing
commit
e46c02d475
|
@ -28,6 +28,7 @@ Semver is not yet in place, so each version can have breaking changes, although
|
|||
- Transvoxel runs faster (almost x2 speedup)
|
||||
- The SDF channel is now 16-bit by default instead of 8-bit, which reduces terracing in big terrains
|
||||
- Optimized `VoxelGeneratorGraph` by making it detect empty blocks more accurately
|
||||
- Added `SdfSphereHeightmap` and `Normalize` nodes to voxel graph, which can help making planets
|
||||
|
||||
- Blocky voxels
|
||||
- Introduced a second blocky mesher dedicated to colored cubes, with greedy meshing and palette support (scripts only)
|
||||
|
|
|
@ -130,7 +130,6 @@ struct PNodeRemap {
|
|||
float p_c0;
|
||||
float p_m0;
|
||||
float p_c1;
|
||||
float p_m1;
|
||||
};
|
||||
|
||||
struct PNodeSmoothstep {
|
||||
|
@ -469,9 +468,8 @@ bool VoxelGraphRuntime::_compile(const ProgramGraph &graph, bool debug) {
|
|||
const float min1 = node->params[2].operator float();
|
||||
const float max1 = node->params[3].operator float();
|
||||
n.p_c0 = -min0;
|
||||
n.p_m0 = Math::is_equal_approx(max0, min0) ? 99999.f : 1.f / (max0 - min0);
|
||||
n.p_m0 = (max1 - min1) * (Math::is_equal_approx(max0, min0) ? 99999.f : 1.f / (max0 - min0));
|
||||
n.p_c1 = min1;
|
||||
n.p_m1 = max1 - min1;
|
||||
} break;
|
||||
|
||||
case VoxelGeneratorGraph::NODE_SMOOTHSTEP: {
|
||||
|
@ -870,7 +868,7 @@ float VoxelGraphRuntime::generate_single(const Vector3 &position) {
|
|||
|
||||
case VoxelGeneratorGraph::NODE_REMAP: {
|
||||
const PNodeRemap &n = read<PNodeRemap>(_program, pc);
|
||||
memory[n.a_out] = ((memory[n.a_x] - n.p_c0) * n.p_m0) * n.p_m1 + n.p_c1;
|
||||
memory[n.a_out] = (memory[n.a_x] - n.p_c0) * n.p_m0 + n.p_c1;
|
||||
} break;
|
||||
|
||||
case VoxelGeneratorGraph::NODE_SMOOTHSTEP: {
|
||||
|
@ -1147,7 +1145,7 @@ Interval VoxelGraphRuntime::analyze_range(Vector3i min_pos, Vector3i max_pos) {
|
|||
case VoxelGeneratorGraph::NODE_REMAP: {
|
||||
const PNodeRemap &n = read<PNodeRemap>(_program, pc);
|
||||
Interval x(min_memory[n.a_x], max_memory[n.a_x]);
|
||||
Interval r = ((x - n.p_c0) * n.p_m0) * n.p_m1 + n.p_c1;
|
||||
Interval r = (x - n.p_c0) * n.p_m0 + n.p_c1;
|
||||
min_memory[n.a_out] = r.min;
|
||||
max_memory[n.a_out] = r.max;
|
||||
} break;
|
||||
|
|
|
@ -885,7 +885,8 @@ void VoxelBuffer::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("fill_f", "value", "channel"), &VoxelBuffer::fill_f, DEFVAL(0));
|
||||
ClassDB::bind_method(D_METHOD("fill_area", "value", "min", "max", "channel"), &VoxelBuffer::_b_fill_area, DEFVAL(0));
|
||||
ClassDB::bind_method(D_METHOD("copy_channel_from", "other", "channel"), &VoxelBuffer::_b_copy_channel_from);
|
||||
ClassDB::bind_method(D_METHOD("copy_channel_from_area", "other", "src_min", "src_max", "dst_min", "channel"), &VoxelBuffer::_b_copy_channel_from_area);
|
||||
ClassDB::bind_method(D_METHOD("copy_channel_from_area", "other", "src_min", "src_max", "dst_min", "channel"),
|
||||
&VoxelBuffer::_b_copy_channel_from_area);
|
||||
ClassDB::bind_method(D_METHOD("downscale_to", "dst", "src_min", "src_max", "dst_min"), &VoxelBuffer::_b_downscale_to);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("is_uniform", "channel"), &VoxelBuffer::is_uniform);
|
||||
|
|
|
@ -77,7 +77,6 @@ public:
|
|||
real_t get_voxel_f(int x, int y, int z, unsigned int channel_index = 0) const;
|
||||
void set_voxel_f(real_t value, int x, int y, int z, unsigned int channel_index = 0);
|
||||
|
||||
Color get_voxel_c(int x, int y, int z, unsigned int channel_index = 0) const;
|
||||
_FORCE_INLINE_ uint64_t get_voxel(const Vector3i pos, unsigned int channel_index = 0) const {
|
||||
return get_voxel(pos.x, pos.y, pos.z, channel_index);
|
||||
}
|
||||
|
|
|
@ -64,6 +64,53 @@ static inline void schedule_mesh_update(VoxelBlock *block, std::vector<Vector3i>
|
|||
}
|
||||
}
|
||||
|
||||
struct BeforeUnloadAction {
|
||||
std::vector<Ref<ShaderMaterial> > shader_material_pool;
|
||||
std::vector<VoxelLodTerrain::BlockToSave> blocks_to_save;
|
||||
|
||||
void operator()(VoxelBlock *block) {
|
||||
// Recycle material
|
||||
Ref<ShaderMaterial> sm = block->get_shader_material();
|
||||
if (sm.is_valid()) {
|
||||
shader_material_pool.push_back(sm);
|
||||
block->set_shader_material(Ref<ShaderMaterial>());
|
||||
}
|
||||
|
||||
// Save if modified
|
||||
// TODO Don't ask for save if the stream doesn't support it!
|
||||
if (block->is_modified()) {
|
||||
//print_line(String("Scheduling save for block {0}").format(varray(block->position.to_vec3())));
|
||||
VoxelLodTerrain::BlockToSave b;
|
||||
// We don't copy since the block will be unloaded anyways
|
||||
b.voxels = block->voxels;
|
||||
b.position = block->position;
|
||||
b.lod = block->lod_index;
|
||||
blocks_to_save.push_back(b);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ScheduleSaveAction {
|
||||
std::vector<VoxelLodTerrain::BlockToSave> blocks_to_save;
|
||||
|
||||
void operator()(VoxelBlock *block) {
|
||||
// Save if modified
|
||||
// TODO Don't ask for save if the stream doesn't support it!
|
||||
if (block->is_modified()) {
|
||||
//print_line(String("Scheduling save for block {0}").format(varray(block->position.to_vec3())));
|
||||
VoxelLodTerrain::BlockToSave b;
|
||||
|
||||
RWLockRead lock(block->voxels->get_lock());
|
||||
b.voxels = block->voxels->duplicate(true);
|
||||
|
||||
b.position = block->position;
|
||||
b.lod = block->lod_index;
|
||||
blocks_to_save.push_back(b);
|
||||
block->set_modified(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
VoxelLodTerrain::VoxelLodTerrain() {
|
||||
|
@ -101,7 +148,15 @@ VoxelLodTerrain::~VoxelLodTerrain() {
|
|||
if (_stream.is_valid()) {
|
||||
// Schedule saving of all modified blocks,
|
||||
// without copy because we are destroying the map anyways
|
||||
save_all_modified_blocks(false);
|
||||
|
||||
flush_pending_lod_edits();
|
||||
|
||||
for (int i = 0; i < _lod_count; ++i) {
|
||||
_lods[i].map.for_all_blocks(BeforeUnloadAction{ _shader_material_pool, _blocks_to_save });
|
||||
}
|
||||
|
||||
// And flush immediately
|
||||
send_block_data_requests();
|
||||
}
|
||||
|
||||
VoxelServer::get_singleton()->remove_volume(_volume_id);
|
||||
|
@ -1323,49 +1378,13 @@ void VoxelLodTerrain::flush_pending_lod_edits() {
|
|||
// }
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct ScheduleSaveAction {
|
||||
std::vector<VoxelLodTerrain::BlockToSave> &blocks_to_save;
|
||||
std::vector<Ref<ShaderMaterial> > &shader_materials;
|
||||
bool with_copy;
|
||||
|
||||
void operator()(VoxelBlock *block) {
|
||||
Ref<ShaderMaterial> sm = block->get_shader_material();
|
||||
if (sm.is_valid()) {
|
||||
// Recycle material
|
||||
shader_materials.push_back(sm);
|
||||
block->set_shader_material(Ref<ShaderMaterial>());
|
||||
}
|
||||
|
||||
// TODO Don't ask for save if the stream doesn't support it!
|
||||
if (block->is_modified()) {
|
||||
//print_line(String("Scheduling save for block {0}").format(varray(block->position.to_vec3())));
|
||||
VoxelLodTerrain::BlockToSave b;
|
||||
|
||||
if (with_copy) {
|
||||
RWLockRead lock(block->voxels->get_lock());
|
||||
b.voxels = block->voxels->duplicate(true);
|
||||
} else {
|
||||
b.voxels = block->voxels;
|
||||
}
|
||||
|
||||
b.position = block->position;
|
||||
b.lod = block->lod_index;
|
||||
blocks_to_save.push_back(b);
|
||||
block->set_modified(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void VoxelLodTerrain::immerge_block(Vector3i block_pos, int lod_index) {
|
||||
VOXEL_PROFILE_SCOPE();
|
||||
|
||||
ERR_FAIL_COND(lod_index >= get_lod_count());
|
||||
|
||||
Lod &lod = _lods[lod_index];
|
||||
|
||||
lod.map.remove_block(block_pos, ScheduleSaveAction{ _blocks_to_save, _shader_material_pool, false });
|
||||
lod.map.remove_block(block_pos, BeforeUnloadAction{ _shader_material_pool, _blocks_to_save });
|
||||
|
||||
lod.loading_blocks.erase(block_pos);
|
||||
|
||||
|
@ -1386,7 +1405,7 @@ void VoxelLodTerrain::save_all_modified_blocks(bool with_copy) {
|
|||
|
||||
for (int i = 0; i < _lod_count; ++i) {
|
||||
// That may cause a stutter, so should be used when the player won't notice
|
||||
_lods[i].map.for_all_blocks(ScheduleSaveAction{ _blocks_to_save, _shader_material_pool, with_copy });
|
||||
_lods[i].map.for_all_blocks(ScheduleSaveAction{ _blocks_to_save });
|
||||
}
|
||||
|
||||
// And flush immediately
|
||||
|
|
|
@ -97,9 +97,6 @@ public:
|
|||
|
||||
const Stats &get_stats() const;
|
||||
|
||||
void set_run_stream_in_editor(bool enable);
|
||||
bool is_stream_running_in_editor() const;
|
||||
|
||||
void restart_stream() override;
|
||||
void remesh_all_blocks() override;
|
||||
|
||||
|
@ -109,10 +106,17 @@ public:
|
|||
uint8_t lod;
|
||||
};
|
||||
|
||||
// Debugging
|
||||
|
||||
Array debug_raycast_block(Vector3 world_origin, Vector3 world_direction) const;
|
||||
Dictionary debug_get_block_info(Vector3 fbpos, int lod_index) const;
|
||||
Array debug_get_octrees() const;
|
||||
|
||||
// Editor
|
||||
|
||||
void set_run_stream_in_editor(bool enable);
|
||||
bool is_stream_running_in_editor() const;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
void set_show_gizmos(bool enable);
|
||||
bool is_showing_gizmos() const { return _show_gizmos_enabled; }
|
||||
|
|
|
@ -161,6 +161,9 @@ void VoxelMap::remove_block_internal(Vector3i bpos, unsigned int index) {
|
|||
_blocks_map.erase(bpos);
|
||||
|
||||
VoxelBlock *moved_block = _blocks.back();
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(index >= _blocks.size());
|
||||
#endif
|
||||
_blocks[index] = moved_block;
|
||||
_blocks.pop_back();
|
||||
|
||||
|
|
Loading…
Reference in New Issue