diff --git a/doc/source/changelog.md b/doc/source/changelog.md index c8787ab0..fcfae299 100644 --- a/doc/source/changelog.md +++ b/doc/source/changelog.md @@ -22,6 +22,7 @@ Ongoing development - Added `VoxelStreamSQLite`, allowing to save volumes as a single SQLite database - Implemented `copy` and `paste` for `VoxelToolTerrain` - Added ability to double block size used for meshes and instancing, improving rendering speed at the cost of slower modification + - Added collision layer and mask properties - Editor - Streaming/LOD can be set to follow the editor camera instead of being centered on world origin. Use with caution, fast big movements and zooms can cause lag diff --git a/terrain/voxel_lod_terrain.cpp b/terrain/voxel_lod_terrain.cpp index f563e02e..6680c5cd 100644 --- a/terrain/voxel_lod_terrain.cpp +++ b/terrain/voxel_lod_terrain.cpp @@ -588,6 +588,32 @@ int VoxelLodTerrain::get_collision_lod_count() const { return _collision_lod_count; } +void VoxelLodTerrain::set_collision_layer(int layer) { + _collision_layer = layer; + for (unsigned int lod_index = 0; lod_index < _lod_count; ++lod_index) { + _lods[lod_index].mesh_map.for_all_blocks([layer](VoxelMeshBlock *block) { + block->set_collision_layer(layer); + }); + } +} + +int VoxelLodTerrain::get_collision_layer() const { + return _collision_layer; +} + +void VoxelLodTerrain::set_collision_mask(int mask) { + _collision_mask = mask; + for (unsigned int lod_index = 0; lod_index < _lod_count; ++lod_index) { + _lods[lod_index].mesh_map.for_all_blocks([mask](VoxelMeshBlock *block) { + block->set_collision_mask(mask); + }); + } +} + +int VoxelLodTerrain::get_collision_mask() const { + return _collision_mask; +} + int VoxelLodTerrain::get_data_block_region_extent() const { return VoxelServer::get_octree_lod_block_region_extent(_lod_distance, get_data_block_size()); } @@ -1607,6 +1633,8 @@ void VoxelLodTerrain::_process(float delta) { if (_collision_update_delay == 0 || static_cast(now - block->last_collider_update_time) > _collision_update_delay) { block->set_collision_mesh(mesh_data.surfaces, get_tree()->is_debugging_collisions_hint(), this); + block->set_collision_layer(_collision_layer); + block->set_collision_mask(_collision_mask); block->last_collider_update_time = now; block->has_deferred_collider_update = false; block->deferred_collider_data.clear(); @@ -1663,6 +1691,8 @@ void VoxelLodTerrain::process_deferred_collision_updates(uint32_t timeout_msec) if (static_cast(now - block->last_collider_update_time) > _collision_update_delay) { block->set_collision_mesh( block->deferred_collider_data, get_tree()->is_debugging_collisions_hint(), this); + block->set_collision_layer(_collision_layer); + block->set_collision_mask(_collision_mask); block->last_collider_update_time = now; block->has_deferred_collider_update = false; block->deferred_collider_data.clear(); @@ -2418,6 +2448,12 @@ void VoxelLodTerrain::_bind_methods() { ClassDB::bind_method(D_METHOD("get_collision_lod_count"), &VoxelLodTerrain::get_collision_lod_count); ClassDB::bind_method(D_METHOD("set_collision_lod_count", "count"), &VoxelLodTerrain::set_collision_lod_count); + ClassDB::bind_method(D_METHOD("get_collision_layer"), &VoxelLodTerrain::get_collision_layer); + ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &VoxelLodTerrain::set_collision_layer); + + ClassDB::bind_method(D_METHOD("get_collision_mask"), &VoxelLodTerrain::get_collision_mask); + ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &VoxelLodTerrain::set_collision_mask); + ClassDB::bind_method(D_METHOD("get_collision_update_delay"), &VoxelLodTerrain::get_collision_update_delay); ClassDB::bind_method(D_METHOD("set_collision_update_delay", "delay_msec"), &VoxelLodTerrain::set_collision_update_delay); @@ -2494,9 +2530,12 @@ void VoxelLodTerrain::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_collisions"), "set_generate_collisions", "get_generate_collisions"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), + "set_collision_layer", "get_collision_layer"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), + "set_collision_mask", "get_collision_mask"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_lod_count"), "set_collision_lod_count", "get_collision_lod_count"); - // TODO Collision mask and layer ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_update_delay"), "set_collision_update_delay", "get_collision_update_delay"); diff --git a/terrain/voxel_lod_terrain.h b/terrain/voxel_lod_terrain.h index 9521aec8..6be3929f 100644 --- a/terrain/voxel_lod_terrain.h +++ b/terrain/voxel_lod_terrain.h @@ -56,6 +56,12 @@ public: void set_collision_lod_count(int lod_count); int get_collision_lod_count() const; + void set_collision_layer(int layer); + int get_collision_layer() const; + + void set_collision_mask(int mask); + int get_collision_mask() const; + int get_data_block_region_extent() const; int get_mesh_block_region_extent() const; @@ -242,6 +248,8 @@ private: bool _generate_collisions = true; unsigned int _collision_lod_count = 0; + unsigned int _collision_layer = 1; + unsigned int _collision_mask = 1; int _collision_update_delay = 0; VoxelInstancer *_instancer = nullptr; diff --git a/terrain/voxel_mesh_block.cpp b/terrain/voxel_mesh_block.cpp index f46c8457..d2ab61f9 100644 --- a/terrain/voxel_mesh_block.cpp +++ b/terrain/voxel_mesh_block.cpp @@ -281,6 +281,18 @@ void VoxelMeshBlock::set_collision_mesh(Vector surface_arrays, bool debug _static_body.set_shape_enabled(0, _visible); } +void VoxelMeshBlock::set_collision_layer(int layer) { + if (_static_body.is_valid()) { + _static_body.set_collision_layer(layer); + } +} + +void VoxelMeshBlock::set_collision_mask(int mask) { + if (_static_body.is_valid()) { + _static_body.set_collision_mask(mask); + } +} + void VoxelMeshBlock::drop_collision() { if (_static_body.is_valid()) { _static_body.destroy(); diff --git a/terrain/voxel_mesh_block.h b/terrain/voxel_mesh_block.h index 658b080f..52358b44 100644 --- a/terrain/voxel_mesh_block.h +++ b/terrain/voxel_mesh_block.h @@ -67,6 +67,8 @@ public: // Collisions void set_collision_mesh(Vector surface_arrays, bool debug_collision, Spatial *node); + void set_collision_layer(int layer); + void set_collision_mask(int mask); void drop_collision(); // TODO Collision layer and mask diff --git a/terrain/voxel_terrain.cpp b/terrain/voxel_terrain.cpp index 7956a300..eb7fa897 100644 --- a/terrain/voxel_terrain.cpp +++ b/terrain/voxel_terrain.cpp @@ -253,6 +253,28 @@ void VoxelTerrain::set_generate_collisions(bool enabled) { _generate_collisions = enabled; } +void VoxelTerrain::set_collision_layer(int layer) { + _collision_layer = layer; + _mesh_map.for_all_blocks([layer](VoxelMeshBlock *block) { + block->set_collision_layer(layer); + }); +} + +int VoxelTerrain::get_collision_layer() const { + return _collision_layer; +} + +void VoxelTerrain::set_collision_mask(int mask) { + _collision_mask = mask; + _mesh_map.for_all_blocks([mask](VoxelMeshBlock *block) { + block->set_collision_mask(mask); + }); +} + +int VoxelTerrain::get_collision_mask() const { + return _collision_mask; +} + unsigned int VoxelTerrain::get_max_view_distance() const { return _max_view_distance_voxels; } @@ -1169,6 +1191,8 @@ void VoxelTerrain::_process() { block->set_mesh(mesh); if (gen_collisions) { block->set_collision_mesh(collidable_surfaces, get_tree()->is_debugging_collisions_hint(), this); + block->set_collision_layer(_collision_layer); + block->set_collision_mask(_collision_mask); } block->set_visible(true); block->set_parent_visible(is_visible()); @@ -1287,6 +1311,12 @@ void VoxelTerrain::_bind_methods() { ClassDB::bind_method(D_METHOD("get_generate_collisions"), &VoxelTerrain::get_generate_collisions); ClassDB::bind_method(D_METHOD("set_generate_collisions", "enabled"), &VoxelTerrain::set_generate_collisions); + ClassDB::bind_method(D_METHOD("get_collision_layer"), &VoxelTerrain::get_collision_layer); + ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &VoxelTerrain::set_collision_layer); + + ClassDB::bind_method(D_METHOD("get_collision_mask"), &VoxelTerrain::get_collision_mask); + ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &VoxelTerrain::set_collision_mask); + ClassDB::bind_method(D_METHOD("voxel_to_data_block", "voxel_pos"), &VoxelTerrain::_b_voxel_to_data_block); ClassDB::bind_method(D_METHOD("data_block_to_voxel", "block_pos"), &VoxelTerrain::_b_data_block_to_voxel); @@ -1317,6 +1347,10 @@ void VoxelTerrain::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_collisions"), "set_generate_collisions", "get_generate_collisions"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), + "set_collision_layer", "get_collision_layer"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), + "set_collision_mask", "get_collision_mask"); ADD_GROUP("Advanced", ""); diff --git a/terrain/voxel_terrain.h b/terrain/voxel_terrain.h index 359c6817..e02bda1e 100644 --- a/terrain/voxel_terrain.h +++ b/terrain/voxel_terrain.h @@ -44,6 +44,12 @@ public: void set_generate_collisions(bool enabled); bool get_generate_collisions() const { return _generate_collisions; } + void set_collision_layer(int layer); + int get_collision_layer() const; + + void set_collision_mask(int mask); + int get_collision_mask() const; + unsigned int get_max_view_distance() const; void set_max_view_distance(unsigned int distance_in_voxels); @@ -189,6 +195,8 @@ private: Ref _generator; bool _generate_collisions = true; + unsigned int _collision_layer = 1; + unsigned int _collision_mask = 1; bool _run_stream_in_editor = true; //bool _stream_enabled = false; diff --git a/util/godot/direct_static_body.cpp b/util/godot/direct_static_body.cpp index 17608e87..0c5a5849 100644 --- a/util/godot/direct_static_body.cpp +++ b/util/godot/direct_static_body.cpp @@ -93,6 +93,16 @@ void DirectStaticBody::set_attached_object(Object *obj) { PhysicsServer::get_singleton()->body_attach_object_instance_id(_body, obj != nullptr ? obj->get_instance_id() : 0); } +void DirectStaticBody::set_collision_layer(int layer) { + ERR_FAIL_COND(!_body.is_valid()); + PhysicsServer::get_singleton()->body_set_collision_layer(_body, layer); +} + +void DirectStaticBody::set_collision_mask(int mask) { + ERR_FAIL_COND(!_body.is_valid()); + PhysicsServer::get_singleton()->body_set_collision_mask(_body, mask); +} + void DirectStaticBody::set_debug(bool enabled, World *world) { ERR_FAIL_COND(world == nullptr); diff --git a/util/godot/direct_static_body.h b/util/godot/direct_static_body.h index 562de4a3..8442af79 100644 --- a/util/godot/direct_static_body.h +++ b/util/godot/direct_static_body.h @@ -23,6 +23,8 @@ public: void set_world(World *world); void set_shape_enabled(int shape_index, bool disabled); void set_attached_object(Object *obj); + void set_collision_layer(int layer); + void set_collision_mask(int mask); void set_debug(bool enabled, World *world);