diff --git a/meshers/dmc/voxel_mesher_dmc.cpp b/meshers/dmc/voxel_mesher_dmc.cpp index cb15123..41251e8 100644 --- a/meshers/dmc/voxel_mesher_dmc.cpp +++ b/meshers/dmc/voxel_mesher_dmc.cpp @@ -1426,11 +1426,6 @@ void polygonize_volume_directly(const VoxelBuffer &voxels, Vector3i min, Vector3 #define BUILD_OCTREE_BOTTOM_UP VoxelMesherDMC::VoxelMesherDMC() { - - _geometric_error = 0.1; - _mesh_mode = MESH_NORMAL; - _octree_mode = OCTREE_BOTTOM_UP; - _stats = { 0 }; } void VoxelMesherDMC::set_mesh_mode(MeshMode mode) { @@ -1457,6 +1452,14 @@ float VoxelMesherDMC::get_geometric_error() const { return _geometric_error; } +void VoxelMesherDMC::set_seam_mode(SeamMode mode) { + _seam_mode = mode; +} + +VoxelMesherDMC::SeamMode VoxelMesherDMC::get_seam_mode() const { + return _seam_mode; +} + void VoxelMesherDMC::build(VoxelMesher::Output &output, const VoxelBuffer &voxels, int padding) { // Requirements: @@ -1481,7 +1484,15 @@ void VoxelMesherDMC::build(VoxelMesher::Output &output, const VoxelBuffer &voxel ERR_FAIL_COND(voxels.get_size().z < chunk_size + padding * 2); // TODO Option for this in case LOD is not used - bool skirts_enabled = true; + bool skirts_enabled = _seam_mode == SEAM_MARCHING_SQUARE_SKIRTS; + // Marching square skirts are a cheap way to hide LOD cracks, + // however they might still be visible because of shadow mapping, and cause potential issues when used for physics. + // Maybe a shader with a `light()` function can prevent shadows from being applied to these, + // but in longer term, proper seams remain a better solution. + // Unfortunately, such seams require the ability to quickly swap index buffers of the mesh using OpenGL/Vulkan, + // which is not possible with current Godot's VisualServer without forking the whole lot (dang!), + // and we are forced to at least re-upload the mesh entirely or have 16 versions of it just swapping seams... + // So we can't improve this further until Godot's API gives us that possibility, or other approaches like skirts need to be taken. // Construct an intermediate to handle padding transparently dmc::VoxelAccess voxels_access(voxels, Vector3i(padding)); @@ -1601,6 +1612,9 @@ void VoxelMesherDMC::_bind_methods() { ClassDB::bind_method(D_METHOD("set_geometric_error", "error"), &VoxelMesherDMC::set_geometric_error); ClassDB::bind_method(D_METHOD("get_geometric_error"), &VoxelMesherDMC::get_geometric_error); + ClassDB::bind_method(D_METHOD("set_seam_mode", "mode"), &VoxelMesherDMC::set_seam_mode); + ClassDB::bind_method(D_METHOD("get_seam_mode"), &VoxelMesherDMC::get_seam_mode); + ClassDB::bind_method(D_METHOD("get_stats"), &VoxelMesherDMC::get_stats); BIND_ENUM_CONSTANT(MESH_NORMAL); @@ -1611,4 +1625,7 @@ void VoxelMesherDMC::_bind_methods() { BIND_ENUM_CONSTANT(OCTREE_BOTTOM_UP); BIND_ENUM_CONSTANT(OCTREE_TOP_DOWN); BIND_ENUM_CONSTANT(OCTREE_NONE); + + BIND_ENUM_CONSTANT(SEAM_NONE); + BIND_ENUM_CONSTANT(SEAM_MARCHING_SQUARE_SKIRTS); } diff --git a/meshers/dmc/voxel_mesher_dmc.h b/meshers/dmc/voxel_mesher_dmc.h index bc3c6ed..9aab01d 100644 --- a/meshers/dmc/voxel_mesher_dmc.h +++ b/meshers/dmc/voxel_mesher_dmc.h @@ -46,10 +46,7 @@ struct OctreeNode { struct DualCell { Vector3 corners[8]; HermiteValue values[8]; - bool has_values; - - DualCell() : - has_values(false) {} + bool has_values = false; inline void set_corner(int i, Vector3 vertex, HermiteValue value) { CRASH_COND(i < 0 || i >= 8); @@ -64,6 +61,7 @@ struct DualGrid { } // namespace dmc +// Mesher extending Marching Cubes using a dual grid. class VoxelMesherDMC : public VoxelMesher { GDCLASS(VoxelMesherDMC, VoxelMesher) public: @@ -76,12 +74,20 @@ public: MESH_DEBUG_DUAL_GRID }; + // TODO Rename SimplifyMode because octree isn't the only way enum OctreeMode { OCTREE_BOTTOM_UP, OCTREE_TOP_DOWN, OCTREE_NONE }; + enum SeamMode { + SEAM_NONE, // No seam management + SEAM_MARCHING_SQUARE_SKIRTS, // Marching square skirts + // SEAM_OVERLAP // Polygonize extra voxels with lower isolevel + // SEAM_JUNCTION_TRIANGLES // Extra triangles for alternate borders, requires index buffer switching + }; + VoxelMesherDMC(); void set_mesh_mode(MeshMode mode); @@ -93,6 +99,9 @@ public: void set_geometric_error(real_t geometric_error); float get_geometric_error() const; + void set_seam_mode(SeamMode mode); + SeamMode get_seam_mode() const; + void build(VoxelMesher::Output &output, const VoxelBuffer &voxels, int padding) override; int get_minimum_padding() const override; @@ -105,15 +114,16 @@ private: dmc::MeshBuilder _mesh_builder; dmc::DualGrid _dual_grid; dmc::OctreeNodePool _octree_node_pool; - real_t _geometric_error; - MeshMode _mesh_mode; - OctreeMode _octree_mode; + real_t _geometric_error = 0.1; + MeshMode _mesh_mode = MESH_NORMAL; + OctreeMode _octree_mode = OCTREE_BOTTOM_UP; + SeamMode _seam_mode = SEAM_NONE; struct Stats { - real_t octree_build_time; - real_t dualgrid_derivation_time; - real_t meshing_time; - real_t commit_time; + real_t octree_build_time = 0; + real_t dualgrid_derivation_time = 0; + real_t meshing_time = 0; + real_t commit_time = 0; }; Stats _stats; @@ -121,5 +131,6 @@ private: VARIANT_ENUM_CAST(VoxelMesherDMC::OctreeMode) VARIANT_ENUM_CAST(VoxelMesherDMC::MeshMode) +VARIANT_ENUM_CAST(VoxelMesherDMC::SeamMode) #endif // VOXEL_MESHER_DMC_H diff --git a/terrain/voxel_mesh_updater.cpp b/terrain/voxel_mesh_updater.cpp index 531f918..e0273b9 100644 --- a/terrain/voxel_mesh_updater.cpp +++ b/terrain/voxel_mesh_updater.cpp @@ -16,6 +16,7 @@ VoxelMeshUpdater::VoxelMeshUpdater(Ref library, MeshingParams para _dmc_mesher.instance(); _dmc_mesher->set_geometric_error(0.05); _dmc_mesher->set_octree_mode(VoxelMesherDMC::OCTREE_NONE); + _dmc_mesher->set_seam_mode(VoxelMesherDMC::SEAM_MARCHING_SQUARE_SKIRTS); } _input_mutex = Mutex::create();