diff --git a/Cargo.toml b/Cargo.toml index 96e2dd66..7320c4dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ publish = false crate-type = ["cdylib"] [features] -default = ["single-dim2", "serde-serialize"] +default = ["single-dim3", "serde-serialize"] dim2 = [] dim3 = [] single = [] diff --git a/README.md b/README.md index ce87d865..0e04e39a 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,8 @@ The reason it was rewritten is to do easier cross platform determinism part and - Cross platform determinism. - Double builds. - Liquids Missing. -- No support for asymetric collisions (eg. object 1 hitting object 2 but object 2 not hitting object 1). +- No support for asymetric collisions (eg. object 1 hitting object 2 but object 2 not hitting object 1). More info here [Rapier Collision groups and solver groups](https://rapier.rs/docs/user_guides/rust/colliders/#collision-groups-and-solver-groups). This is the exact check rapier does: `(A.layer & B.mask) != 0 && (B.layer & A.mask) != 0` +- Friction works differently than it does in Godot. The current formula is: friction is multiplied by other friction, bounce is taken the max value. # Platforms diff --git a/bin2d/test.tscn b/bin2d/test.tscn index 0b5f6680..9920ad4a 100644 --- a/bin2d/test.tscn +++ b/bin2d/test.tscn @@ -1,63 +1,54 @@ -[gd_scene load_steps=5 format=3 uid="uid://cn4jscixu2bmf"] +[gd_scene load_steps=4 format=3 uid="uid://cn4jscixu2bmf"] -[sub_resource type="GDScript" id="GDScript_gph3d"] -script/source = "extends Node2D +[sub_resource type="CircleShape2D" id="CircleShape2D_lc8oa"] +[sub_resource type="RectangleShape2D" id="RectangleShape2D_irytb"] -func _ready() -> void: - var space := get_viewport().find_world_2d().direct_space_state as RapierDirectSpaceState2D - var space_json := FileAccess.open(\"user://space.json\", FileAccess.WRITE) - var shapes_json := FileAccess.open(\"user://shapes.json\", FileAccess.WRITE) - #space_json.store_string(space.export_json()) - #shapes_json.store_string(RapierPhysicsServer2D.shapes_export_json()) -" - -[sub_resource type="CircleShape2D" id="CircleShape2D_ykjo6"] - -[sub_resource type="CircleShape2D" id="CircleShape2D_6y2xx"] - -[sub_resource type="GDScript" id="GDScript_swyq8"] -script/source = "extends ShapeCast2D - - -# Called when the node enters the scene tree for the first time. -func _ready() -> void: - pass # Replace with function body. - - -# Called every frame. 'delta' is the elapsed time since the previous frame. -func _process(delta: float) -> void: - print(get_collision_count()) - print(get_collision_point(0)) - print(get_collision_point(1)) -" +[sub_resource type="WorldBoundaryShape2D" id="WorldBoundaryShape2D_ila5n"] +normal = Vector2(-0.0425147, -0.999096) [node name="SceneRayOnSwitch" type="Node2D"] -[node name="Node2D" type="Node2D" parent="."] -script = SubResource("GDScript_gph3d") - -[node name="Node2D2" type="Node2D" parent="."] - -[node name="RigidBody2D" type="StaticBody2D" parent="."] -position = Vector2(133, 63) - -[node name="CollisionShape2D" type="CollisionShape2D" parent="RigidBody2D"] -position = Vector2(65, 27) -shape = SubResource("CircleShape2D_ykjo6") - -[node name="RigidBody2D2" type="StaticBody2D" parent="."] -position = Vector2(132, 67) +[node name="RigidBody2D2" type="RigidBody2D" parent="."] +position = Vector2(-54, -682) +rotation = -1.51672 +scale = Vector2(4, 2.51) +mass = 100.0 +max_contacts_reported = 1 [node name="CollisionShape2D" type="CollisionShape2D" parent="RigidBody2D2"] -position = Vector2(65, 27) -shape = SubResource("CircleShape2D_ykjo6") - -[node name="ShapeCast" type="ShapeCast2D" parent="."] -position = Vector2(123, 62) -shape = SubResource("CircleShape2D_6y2xx") -target_position = Vector2(205, 82) -script = SubResource("GDScript_swyq8") - -[node name="Marker2D" type="Marker2D" parent="."] -position = Vector2(207, 92) +position = Vector2(-89, 3) +scale = Vector2(1.89, 1) +shape = SubResource("CircleShape2D_lc8oa") + +[node name="CollisionShape2D2" type="CollisionShape2D" parent="RigidBody2D2"] +position = Vector2(-88.2483, 25.9664) +scale = Vector2(1.89, 1) +shape = SubResource("CircleShape2D_lc8oa") + +[node name="CollisionShape2D3" type="CollisionShape2D" parent="RigidBody2D2"] +position = Vector2(-87.2888, 54.2119) +scale = Vector2(1.89, 1) +shape = SubResource("CircleShape2D_lc8oa") + +[node name="RigidBody2D3" type="RigidBody2D" parent="."] +position = Vector2(-80, -513) +rotation = -1.51672 +scale = Vector2(4, 2.51) +max_contacts_reported = 1 + +[node name="CollisionShape2D" type="CollisionShape2D" parent="RigidBody2D3"] +position = Vector2(-89, 3) +scale = Vector2(1.89, 1) +shape = SubResource("RectangleShape2D_irytb") + +[node name="StaticBody2D" type="StaticBody2D" parent="."] +position = Vector2(-1, 55) + +[node name="CollisionShape2D" type="CollisionShape2D" parent="StaticBody2D"] +position = Vector2(-6, 61) +rotation = -0.060205 +shape = SubResource("WorldBoundaryShape2D_ila5n") + +[node name="Camera2D" type="Camera2D" parent="."] +zoom = Vector2(2, 2) diff --git a/src/bodies/rapier_area.rs b/src/bodies/rapier_area.rs index 864fa9a3..97e68432 100644 --- a/src/bodies/rapier_area.rs +++ b/src/bodies/rapier_area.rs @@ -374,26 +374,13 @@ impl RapierArea { if let Some(space) = physics_spaces.get_mut(&space_rid) { space.area_remove_from_area_update_list(*area_rid); } - for (detected_body, _) in detected_bodies { - let mut area_override_settings = None; - if let Some(body) = physics_collision_objects.get(&detected_body) { - if let Some(body) = body.get_body() { - area_override_settings = Some( - body.get_area_override_settings(physics_spaces, physics_collision_objects), - ); - } - } - if let Some(area_override_settings) = area_override_settings { - if let Some(body) = physics_collision_objects.get_mut(&detected_body) { - if let Some(body) = body.get_mut_body() { - body.apply_area_override( - area_override_settings, - physics_engine, - physics_spaces, - ); - } - } - } + for (detected_body, _) in &detected_bodies { + RapierBody::apply_area_orverride_to_body( + detected_body, + physics_engine, + physics_spaces, + physics_collision_objects, + ); } } @@ -713,7 +700,7 @@ impl IRapierCollisionObject for RapierArea { return; } self.base.set_space(p_space, physics_engine, physics_spaces); - self.recreate_shapes(physics_engine, physics_shapes); + self.recreate_shapes(physics_engine, physics_shapes, physics_spaces); } fn add_shape( @@ -831,7 +818,7 @@ impl IRapierCollisionObject for RapierArea { physics_engine: &mut PhysicsEngine, physics_shapes: &mut PhysicsShapes, ) -> ColliderHandle { - if !self.base.is_space_valid() { + if !self.base.is_valid() { return ColliderHandle::invalid(); } let mat = self.init_material(); @@ -840,15 +827,24 @@ impl IRapierCollisionObject for RapierArea { } fn init_material(&self) -> Material { - default_material() + Material::new( + self.base.get_collision_layer(), + self.base.get_collision_mask(), + ) } fn recreate_shapes( &mut self, physics_engine: &mut PhysicsEngine, physics_shapes: &mut PhysicsShapes, + physics_spaces: &mut PhysicsSpaces, ) { - RapierCollisionObject::recreate_shapes(self, physics_engine, physics_shapes); + RapierCollisionObject::recreate_shapes( + self, + physics_engine, + physics_shapes, + physics_spaces, + ); } fn shape_changed( diff --git a/src/bodies/rapier_body.rs b/src/bodies/rapier_body.rs index 3c3f786b..d6260f9c 100644 --- a/src/bodies/rapier_body.rs +++ b/src/bodies/rapier_body.rs @@ -440,6 +440,33 @@ impl RapierBody { space.body_add_to_area_update_list(self.base.get_rid()); } + pub fn apply_area_orverride_to_body( + body: &Rid, + physics_engine: &mut PhysicsEngine, + physics_spaces: &mut PhysicsSpaces, + physics_collision_objects: &mut PhysicsCollisionObjects, + ) { + let mut area_override_settings = None; + if let Some(body) = physics_collision_objects.get(body) { + if let Some(body) = body.get_body() { + area_override_settings = Some( + body.get_area_override_settings(physics_spaces, physics_collision_objects), + ); + } + } + if let Some(area_override_settings) = area_override_settings { + if let Some(body) = physics_collision_objects.get_mut(body) { + if let Some(body) = body.get_mut_body() { + body.apply_area_override( + area_override_settings, + physics_engine, + physics_spaces, + ); + } + } + } + } + pub fn get_area_override_settings( &self, physics_spaces: &mut PhysicsSpaces, @@ -462,7 +489,8 @@ impl RapierBody { let mut linear_damping_done = self.linear_damping_mode == BodyDampMode::REPLACE; let mut angular_damping_done = self.angular_damping_mode == BodyDampMode::REPLACE; let origin = self.get_base().get_transform().origin; - if ac > 0 { + // only compute if we don't omit force integration + if ac > 0 && !self.omit_force_integration { let mut areas = self.areas.clone(); areas.reverse(); for area_rid in areas.iter() { @@ -548,8 +576,13 @@ impl RapierBody { } } // Override or combine damping with body's values. - total_linear_damping += self.linear_damping; - total_angular_damping += self.angular_damping; + if !self.omit_force_integration { + total_linear_damping += self.linear_damping; + total_angular_damping += self.angular_damping; + } else { + linear_damping_done = true; + angular_damping_done = true; + } AreaOverrideSettings { using_area_gravity, using_area_linear_damping, @@ -597,8 +630,16 @@ impl RapierBody { physics_engine, physics_spaces, ); + if self.omit_force_integration || self.using_area_gravity { + self.apply_gravity_scale(0.0, physics_engine); + } else { + // Enable simulation gravity. + self.apply_gravity_scale(self.gravity_scale, physics_engine); + } if let Some(space) = physics_spaces.get_mut(&self.base.get_space()) { - if self.using_area_gravity { + if self.omit_force_integration { + space.body_remove_from_gravity_update_list(self.base.get_rid()); + } else if self.using_area_gravity { // Add default gravity from space. if !gravity_done { self.total_gravity += space.get_default_area_param(AreaParameter::GRAVITY).to(); @@ -606,11 +647,8 @@ impl RapierBody { // Apply gravity scale to computed value. self.total_gravity *= self.gravity_scale; // Disable simulation gravity and apply it manually instead. - self.apply_gravity_scale(0.0, physics_engine); space.body_add_to_gravity_update_list(self.base.get_rid()); } else { - // Enable simulation gravity. - self.apply_gravity_scale(self.gravity_scale, physics_engine); space.body_remove_from_gravity_update_list(self.base.get_rid()); } } @@ -1326,6 +1364,7 @@ impl RapierBody { p_variant: Variant, physics_engine: &mut PhysicsEngine, physics_spaces: &mut PhysicsSpaces, + physics_shapes: &mut PhysicsShapes, ) { match p_state { BodyState::TRANSFORM => { @@ -1339,8 +1378,13 @@ impl RapierBody { godot_error!("Invalid body data."); return; } + let old_scale = transform_scale(&self.base.get_transform()); let transform = p_variant.to(); + let new_scale = transform_scale(&transform); self.base.set_transform(transform, true, physics_engine); + if old_scale != new_scale { + self.recreate_shapes(physics_engine, physics_shapes, physics_spaces); + } } BodyState::LINEAR_VELOCITY => { #[cfg(feature = "dim2")] @@ -1682,8 +1726,11 @@ impl RapierBody { self.contact_count } - pub fn contacts(&self) -> &Vec { - &self.contacts + pub fn contacts(&self) -> Vec<&Contact> { + self.contacts + .iter() + .take(self.contact_count as usize) + .collect() } fn set_space_before(&mut self, physics_spaces: &mut PhysicsSpaces) { @@ -1715,22 +1762,28 @@ impl RapierBody { self.force_sleep(physics_engine); } if self.base.mode.ord() >= BodyMode::RIGID.ord() { - self.apply_gravity_scale(self.gravity_scale, physics_engine); - if self.linear_damping_mode == BodyDampMode::COMBINE { - self.apply_linear_damping( - self.linear_damping, - true, - physics_engine, - physics_spaces, - ); - } - if self.angular_damping_mode == BodyDampMode::COMBINE { - self.apply_angular_damping( - self.angular_damping, - true, - physics_engine, - physics_spaces, - ); + if self.omit_force_integration { + self.apply_gravity_scale(0.0, physics_engine); + self.apply_linear_damping(0.0, false, physics_engine, physics_spaces); + self.apply_linear_damping(0.0, false, physics_engine, physics_spaces); + } else { + self.apply_gravity_scale(self.gravity_scale, physics_engine); + if self.linear_damping_mode == BodyDampMode::COMBINE { + self.apply_linear_damping( + self.linear_damping, + true, + physics_engine, + physics_spaces, + ); + } + if self.angular_damping_mode == BodyDampMode::COMBINE { + self.apply_angular_damping( + self.angular_damping, + true, + physics_engine, + physics_spaces, + ); + } } self.mass_properties_changed(physics_engine, physics_spaces); if self.linear_velocity != Vector::default() { @@ -1801,7 +1854,7 @@ impl IRapierCollisionObject for RapierBody { } self.set_space_before(physics_spaces); self.base.set_space(space, physics_engine, physics_spaces); - self.recreate_shapes(physics_engine, physics_shapes); + self.recreate_shapes(physics_engine, physics_shapes, physics_spaces); self.set_space_after(physics_engine, physics_spaces); } @@ -1920,7 +1973,7 @@ impl IRapierCollisionObject for RapierBody { physics_engine: &mut PhysicsEngine, physics_shapes: &mut PhysicsShapes, ) -> ColliderHandle { - if !self.base.is_space_valid() { + if !self.base.is_valid() { return ColliderHandle::invalid(); } let mat = self.init_material(); @@ -1935,8 +1988,17 @@ impl IRapierCollisionObject for RapierBody { &mut self, physics_engine: &mut PhysicsEngine, physics_shapes: &mut PhysicsShapes, + physics_spaces: &mut PhysicsSpaces, ) { - RapierCollisionObject::recreate_shapes(self, physics_engine, physics_shapes); + if !self.base.is_valid() { + return; + } + RapierCollisionObject::recreate_shapes( + self, + physics_engine, + physics_shapes, + physics_spaces, + ); } fn init_material(&self) -> Material { @@ -1944,6 +2006,8 @@ impl IRapierCollisionObject for RapierBody { friction: self.friction, restitution: self.bounce, contact_skin: self.contact_skin, + collision_layer: self.base.get_collision_layer(), + collision_mask: self.base.get_collision_mask(), } } diff --git a/src/bodies/rapier_collision_object.rs b/src/bodies/rapier_collision_object.rs index f7222cfa..9b1af264 100644 --- a/src/bodies/rapier_collision_object.rs +++ b/src/bodies/rapier_collision_object.rs @@ -32,6 +32,7 @@ pub trait IRapierCollisionObject: Sync { &mut self, physics_engine: &mut PhysicsEngine, physics_shapes: &mut PhysicsShapes, + physics_spaces: &mut PhysicsSpaces, ); fn add_shape( &mut self, @@ -149,7 +150,6 @@ pub struct RapierCollisionObject { inv_transform: Transform, collision_mask: u32, collision_layer: u32, - collision_priority: real, // TODO serialize this #[cfg_attr(feature = "serde-serialize", serde(skip))] pub(crate) mode: BodyMode, @@ -180,7 +180,6 @@ impl RapierCollisionObject { inv_transform: Transform::default(), collision_mask: 1, collision_layer: 1, - collision_priority: 1.0, mode, body_handle: RigidBodyHandle::invalid(), space_handle: WorldHandle::default(), @@ -312,7 +311,15 @@ impl RapierCollisionObject { godot_error!("Rapier shape is invalid"); return; } - let shape_info = shape_info_from_body_shape(shape_handle, shape.xform); + let scale = transform_scale(&self.transform); + let mut shape_info = shape_info_from_body_shape(shape_handle, shape.xform); + shape_info.scale = vector_to_rapier(vector_to_godot(shape_info.scale) * scale); + let position = shape_info + .transform + .translation + .vector + .component_mul(&vector_to_rapier(scale)); + shape_info.transform.translation.vector = position; physics_engine.collider_set_transform( self.space_handle, shape.collider_handle, @@ -530,33 +537,30 @@ impl RapierCollisionObject { 0.0 } - pub fn set_collision_mask(&mut self, p_mask: u32) { + pub fn set_collision_mask(&mut self, p_mask: u32, physics_engine: &mut PhysicsEngine) { self.collision_mask = p_mask; + if self.is_valid() { + let material = Material::new(self.collision_layer, self.collision_mask); + physics_engine.body_update_material(self.space_handle, self.body_handle, &material); + } } pub fn get_collision_mask(&self) -> u32 { self.collision_mask } - pub fn set_collision_layer(&mut self, p_layer: u32) { + pub fn set_collision_layer(&mut self, p_layer: u32, physics_engine: &mut PhysicsEngine) { self.collision_layer = p_layer; + if self.is_valid() { + let material = Material::new(self.collision_layer, self.collision_mask); + physics_engine.body_update_material(self.space_handle, self.body_handle, &material); + } } pub fn get_collision_layer(&self) -> u32 { self.collision_layer } - pub fn set_collision_priority(&mut self, p_priority: real) { - if p_priority < 0.0 { - return; - } - self.collision_priority = p_priority; - } - - pub fn get_collision_priority(&self) -> real { - self.collision_priority - } - pub fn get_mode(&self) -> BodyMode { self.mode } @@ -565,11 +569,6 @@ impl RapierCollisionObject { self.pickable = p_pickable; } - pub fn interacts_with(&self, p_other: &RapierCollisionObject) -> bool { - self.collision_layer & p_other.collision_mask != 0 - || p_other.collision_layer & self.collision_mask != 0 - } - pub fn destroy_body(&mut self, physics_engine: &mut PhysicsEngine) { if self.body_handle != RigidBodyHandle::invalid() { physics_engine.body_destroy(self.space_handle, self.body_handle); diff --git a/src/bodies/rapier_collision_object_impl.rs b/src/bodies/rapier_collision_object_impl.rs index f1704251..19e05f2f 100644 --- a/src/bodies/rapier_collision_object_impl.rs +++ b/src/bodies/rapier_collision_object_impl.rs @@ -13,11 +13,21 @@ impl RapierCollisionObject { collision_object: &mut dyn IRapierCollisionObject, physics_engine: &mut PhysicsEngine, physics_shapes: &mut PhysicsShapes, + physics_spaces: &mut PhysicsSpaces, ) { for i in 0..collision_object.get_base().get_shape_count() as usize { if collision_object.get_base().shapes[i].disabled { continue; } + if collision_object.get_base().shapes[i].collider_handle != ColliderHandle::invalid() { + collision_object.get_mut_base().shapes[i].collider_handle = + collision_object.get_base().destroy_shape( + collision_object.get_base().shapes[i], + i, + physics_spaces, + physics_engine, + ); + } collision_object.get_mut_base().shapes[i].collider_handle = collision_object .create_shape( collision_object.get_base().shapes[i], @@ -25,10 +35,6 @@ impl RapierCollisionObject { physics_engine, physics_shapes, ); - if collision_object.get_base().shapes[i].collider_handle == ColliderHandle::invalid() { - collision_object.get_mut_base().shapes[i].disabled = true; - continue; - } collision_object.get_base().update_shape_transform( &collision_object.get_base().shapes[i], physics_engine, diff --git a/src/fluids/mod.rs b/src/fluids/mod.rs index 04968320..a6a28458 100644 --- a/src/fluids/mod.rs +++ b/src/fluids/mod.rs @@ -1,11 +1,11 @@ -//#[cfg(feature = "dim2")] -//pub mod fluid_2d; -//pub mod fluid_effect; -//pub mod fluid_effect_elasticity; -//pub mod fluid_effect_surface_tension_akinci; -//pub mod fluid_effect_surface_tension_he; -//pub mod fluid_effect_surface_tension_wcsph; -//pub mod fluid_effect_viscosity_artificial; -//pub mod fluid_effect_viscosity_dfsph; -//pub mod fluid_effect_viscosity_xsph; +#[cfg(feature = "dim2")] +pub mod fluid_2d; +pub mod fluid_effect; +pub mod fluid_effect_elasticity; +pub mod fluid_effect_surface_tension_akinci; +pub mod fluid_effect_surface_tension_he; +pub mod fluid_effect_surface_tension_wcsph; +pub mod fluid_effect_viscosity_artificial; +pub mod fluid_effect_viscosity_dfsph; +pub mod fluid_effect_viscosity_xsph; pub mod rapier_fluid; diff --git a/src/rapier_wrapper/body.rs b/src/rapier_wrapper/body.rs index 105f9163..2785d5cd 100644 --- a/src/rapier_wrapper/body.rs +++ b/src/rapier_wrapper/body.rs @@ -219,6 +219,10 @@ impl PhysicsEngine { if mat.contact_skin >= 0.0 { col.set_contact_skin(mat.contact_skin); } + col.set_collision_groups(InteractionGroups { + memberships: Group::from(mat.collision_layer), + filter: Group::from(mat.collision_mask), + }); } } } diff --git a/src/rapier_wrapper/collider.rs b/src/rapier_wrapper/collider.rs index dffe44e0..3018b9b6 100644 --- a/src/rapier_wrapper/collider.rs +++ b/src/rapier_wrapper/collider.rs @@ -133,7 +133,7 @@ pub fn scale_shape(shape: &SharedShape, shape_info: ShapeInfo) -> SharedShape { ShapeType::Compound => { if let Some(new_shape) = shape.as_compound() { let new_shapes = new_shape.shapes(); - let mut shapes_vec = Vec::<(Isometry, SharedShape)>::new(); + let mut shapes_vec = Vec::new(); for shape in new_shapes { let new_shape = scale_shape(&shape.1, shape_info); shapes_vec.push((shape.0, new_shape)); @@ -150,7 +150,7 @@ pub fn scale_shape(shape: &SharedShape, shape_info: ShapeInfo) -> SharedShape { #[cfg(feature = "dim3")] pub fn scale_shape(shape: &SharedShape, shape_info: ShapeInfo) -> SharedShape { let scale = shape_info.scale; - if scale.x == 1.0 && scale.y == 1.0 { + if scale.x == 1.0 && scale.y == 1.0 && scale.z == 1.0 { return shape.clone(); } match shape.shape_type() { @@ -219,12 +219,18 @@ pub struct Material { pub friction: Real, pub restitution: Real, pub contact_skin: Real, + pub collision_mask: u32, + pub collision_layer: u32, } -pub fn default_material() -> Material { - Material { - friction: 1.0, - restitution: 0.0, - contact_skin: 0.0, +impl Material { + pub fn new(collision_layer: u32, collision_mask: u32) -> Material { + Material { + friction: -1.0, + restitution: -1.0, + contact_skin: -1.0, + collision_layer, + collision_mask, + } } } fn shape_is_halfspace(shape: &SharedShape) -> bool { @@ -263,10 +269,9 @@ impl PhysicsEngine { collider.set_friction_combine_rule(CoefficientCombineRule::Multiply); collider.set_restitution_combine_rule(CoefficientCombineRule::Max); collider.set_density(0.0); - // less data to serialize collider.set_collision_groups(InteractionGroups { - memberships: Group::GROUP_1, - filter: Group::GROUP_1, + memberships: Group::from(mat.collision_layer), + filter: Group::from(mat.collision_mask), }); collider.set_solver_groups(InteractionGroups { memberships: Group::GROUP_1, diff --git a/src/rapier_wrapper/physics_hooks.rs b/src/rapier_wrapper/physics_hooks.rs index 2bafba1b..ed9e70cd 100644 --- a/src/rapier_wrapper/physics_hooks.rs +++ b/src/rapier_wrapper/physics_hooks.rs @@ -23,7 +23,6 @@ pub struct CollisionFilterInfo { } pub struct PhysicsHooksCollisionFilter<'a> { pub collision_filter_body_callback: &'a CollisionFilterCallback, - pub collision_filter_sensor_callback: &'a CollisionFilterCallback, pub collision_modify_contacts_callback: &'a CollisionModifyContactsCallback, pub physics_collision_objects: &'a PhysicsCollisionObjects, } @@ -47,21 +46,6 @@ impl<'a> PhysicsHooks for PhysicsHooksCollisionFilter<'a> { result } - fn filter_intersection_pair(&self, context: &PairFilterContext) -> bool { - let Some(collider1) = context.colliders.get(context.collider1) else { - return false; - }; - let Some(collider2) = context.colliders.get(context.collider2) else { - return false; - }; - let filter_info = CollisionFilterInfo { - user_data1: UserData::new(collider1.user_data), - user_data2: UserData::new(collider2.user_data), - }; - // Handle intersection filtering for sensors - (self.collision_filter_sensor_callback)(&filter_info, self.physics_collision_objects) - } - fn modify_solver_contacts(&self, context: &mut ContactModificationContext) { let Some(rididbody1_handle) = context.rigid_body1 else { return; diff --git a/src/rapier_wrapper/physics_world.rs b/src/rapier_wrapper/physics_world.rs index f26e26fe..c44c9499 100644 --- a/src/rapier_wrapper/physics_world.rs +++ b/src/rapier_wrapper/physics_world.rs @@ -3,6 +3,7 @@ use std::num::NonZeroUsize; use godot::log::godot_print; use rapier::crossbeam; use rapier::data::Arena; +use rapier::math::DEFAULT_EPSILON; use rapier::prelude::*; use salva::integrations::rapier::FluidsPipeline; @@ -101,7 +102,6 @@ impl PhysicsWorld { &mut self, settings: &SimulationSettings, collision_filter_body_callback: CollisionFilterCallback, - collision_filter_sensor_callback: CollisionFilterCallback, collision_modify_contacts_callback: CollisionModifyContactsCallback, space: &mut RapierSpace, physics_collision_objects: &mut PhysicsCollisionObjects, @@ -121,7 +121,6 @@ impl PhysicsWorld { let liquid_gravity = settings.pixel_liquid_gravity; let physics_hooks = PhysicsHooksCollisionFilter { collision_filter_body_callback: &collision_filter_body_callback, - collision_filter_sensor_callback: &collision_filter_sensor_callback, collision_modify_contacts_callback: &collision_modify_contacts_callback, physics_collision_objects, }; @@ -223,6 +222,9 @@ impl PhysicsWorld { contact_info.normal = manifold_normal; // Read the geometric contacts. for contact_point in &manifold.points { + if contact_point.dist > DEFAULT_EPSILON { + continue; + } let collider_pos_1 = collider1.position() * contact_point.local_p1; let collider_pos_2 = collider2.position() * contact_point.local_p2; let point_velocity_1 = body1.velocity_at_point(&collider_pos_1); @@ -456,7 +458,6 @@ impl PhysicsEngine { world_handle: WorldHandle, settings: &SimulationSettings, collision_filter_body_callback: CollisionFilterCallback, - collision_filter_sensor_callback: CollisionFilterCallback, collision_modify_contacts_callback: CollisionModifyContactsCallback, space: &mut RapierSpace, physics_collision_objects: &mut PhysicsCollisionObjects, @@ -465,7 +466,6 @@ impl PhysicsEngine { physics_world.step( settings, collision_filter_body_callback, - collision_filter_sensor_callback, collision_modify_contacts_callback, space, physics_collision_objects, diff --git a/src/servers/rapier_physics_server_extra.rs b/src/servers/rapier_physics_server_extra.rs index 568c74ff..9cd6a8cb 100644 --- a/src/servers/rapier_physics_server_extra.rs +++ b/src/servers/rapier_physics_server_extra.rs @@ -170,13 +170,12 @@ impl RapierPhysicsServer { }; let physics_data = &mut physics_singleton.bind_mut().implementation.physics_data; let values = physics_data.spaces.values().clone().collect::>(); - match serde_json::to_string(&values) { - Ok(s) => s, - Err(err) => { - godot_error!("{}", err); - "{}".to_string() - } - } + let values = values + .iter() + .map(|space| space.export_json(&mut physics_data.physics_engine)) + .collect::>() + .join("},{"); + format!("[{{{}}}]", values) } #[cfg(feature = "serde-serialize")] diff --git a/src/servers/rapier_physics_server_impl.rs b/src/servers/rapier_physics_server_impl.rs index 14c6a2cc..fa1687d6 100644 --- a/src/servers/rapier_physics_server_impl.rs +++ b/src/servers/rapier_physics_server_impl.rs @@ -486,7 +486,8 @@ impl RapierPhysicsServerImpl { pub(super) fn area_set_collision_layer(&mut self, area: Rid, layer: u32) { if let Some(area) = self.physics_data.collision_objects.get_mut(&area) { - area.get_mut_base().set_collision_layer(layer); + area.get_mut_base() + .set_collision_layer(layer, &mut self.physics_data.physics_engine); } } @@ -499,7 +500,8 @@ impl RapierPhysicsServerImpl { pub(super) fn area_set_collision_mask(&mut self, area: Rid, mask: u32) { if let Some(area) = self.physics_data.collision_objects.get_mut(&area) { - area.get_mut_base().set_collision_mask(mask); + area.get_mut_base() + .set_collision_mask(mask, &mut self.physics_data.physics_engine); } } @@ -584,26 +586,12 @@ impl RapierPhysicsServerImpl { &mut self.physics_data.spaces, ); } - let mut area_override_settings = None; - if let Some(body) = self.physics_data.collision_objects.get(&body) - && let Some(body) = body.get_body() - { - area_override_settings = Some(body.get_area_override_settings( - &mut self.physics_data.spaces, - &self.physics_data.collision_objects, - )); - } - if let Some(body) = self.physics_data.collision_objects.get_mut(&body) - && let Some(body) = body.get_mut_body() - { - if let Some(area_override_settings) = area_override_settings { - body.apply_area_override( - area_override_settings, - &mut self.physics_data.physics_engine, - &mut self.physics_data.spaces, - ); - } - } + RapierBody::apply_area_orverride_to_body( + &body, + &mut self.physics_data.physics_engine, + &mut self.physics_data.spaces, + &mut self.physics_data.collision_objects, + ); } pub(super) fn body_get_mode(&self, body: Rid) -> BodyMode { @@ -829,7 +817,8 @@ impl RapierPhysicsServerImpl { pub(super) fn body_set_collision_layer(&mut self, body: Rid, layer: u32) { if let Some(body) = self.physics_data.collision_objects.get_mut(&body) { - body.get_mut_base().set_collision_layer(layer); + body.get_mut_base() + .set_collision_layer(layer, &mut self.physics_data.physics_engine); } } @@ -842,7 +831,8 @@ impl RapierPhysicsServerImpl { pub(super) fn body_set_collision_mask(&mut self, body: Rid, mask: u32) { if let Some(body) = self.physics_data.collision_objects.get_mut(&body) { - body.get_mut_base().set_collision_mask(mask); + body.get_mut_base() + .set_collision_mask(mask, &mut self.physics_data.physics_engine); } } @@ -853,16 +843,9 @@ impl RapierPhysicsServerImpl { 0 } - pub(super) fn body_set_collision_priority(&mut self, body: Rid, priority: f32) { - if let Some(body) = self.physics_data.collision_objects.get_mut(&body) { - body.get_mut_base().set_collision_priority(priority); - } - } + pub(super) fn body_set_collision_priority(&mut self, _body: Rid, _priority: f32) {} - pub(super) fn body_get_collision_priority(&self, body: Rid) -> f32 { - if let Some(body) = self.physics_data.collision_objects.get(&body) { - return body.get_base().get_collision_priority(); - } + pub(super) fn body_get_collision_priority(&self, _body: Rid) -> f32 { 0.0 } @@ -907,6 +890,7 @@ impl RapierPhysicsServerImpl { value, &mut self.physics_data.physics_engine, &mut self.physics_data.spaces, + &mut self.physics_data.shapes, ); } } @@ -1161,6 +1145,12 @@ impl RapierPhysicsServerImpl { body.set_omit_force_integration(enable); } } + RapierBody::apply_area_orverride_to_body( + &body, + &mut self.physics_data.physics_engine, + &mut self.physics_data.spaces, + &mut self.physics_data.collision_objects, + ); } pub(super) fn body_is_omitting_force_integration(&self, body: Rid) -> bool { @@ -1354,11 +1344,14 @@ impl RapierPhysicsServerImpl { body_b, &mut self.physics_data.physics_engine, )); - if let Some(prev_joint) = self.physics_data.joints.remove(&rid) { + if let Some(mut prev_joint) = self.physics_data.joints.remove(&rid) { joint.get_mut_base().copy_settings_from( prev_joint.get_base(), &mut self.physics_data.physics_engine, ); + prev_joint + .get_mut_base() + .destroy_joint(&mut self.physics_data.physics_engine); } } else { joint = Box::new(RapierEmptyJoint::new()); @@ -1388,11 +1381,14 @@ impl RapierPhysicsServerImpl { body_b, &mut self.physics_data.physics_engine, )); - if let Some(prev_joint) = self.physics_data.joints.remove(&rid) { + if let Some(mut prev_joint) = self.physics_data.joints.remove(&rid) { joint.get_mut_base().copy_settings_from( prev_joint.get_base(), &mut self.physics_data.physics_engine, ); + prev_joint + .get_mut_base() + .destroy_joint(&mut self.physics_data.physics_engine); } } else { joint = Box::new(RapierEmptyJoint::new()); @@ -1420,11 +1416,14 @@ impl RapierPhysicsServerImpl { body_b, &mut self.physics_data.physics_engine, )); - if let Some(prev_joint) = self.physics_data.joints.remove(&rid) { + if let Some(mut prev_joint) = self.physics_data.joints.remove(&rid) { joint.get_mut_base().copy_settings_from( prev_joint.get_base(), &mut self.physics_data.physics_engine, ); + prev_joint + .get_mut_base() + .destroy_joint(&mut self.physics_data.physics_engine); } } else { joint = Box::new(RapierEmptyJoint::new()); diff --git a/src/spaces/rapier_space.rs b/src/spaces/rapier_space.rs index 823a84a3..76f0382f 100644 --- a/src/spaces/rapier_space.rs +++ b/src/spaces/rapier_space.rs @@ -1,4 +1,5 @@ use bodies::rapier_area::RapierArea; +use bodies::rapier_body::RapierBody; use godot::classes::ProjectSettings; #[cfg(feature = "dim2")] use godot::engine::physics_server_2d::*; @@ -295,29 +296,13 @@ impl RapierSpace { } } space.reset_mass_properties_update_list(); - for body in body_area_update_list { - let area_override_settings; - if let Some(body) = physics_data.collision_objects.get(&body) - && let Some(body) = body.get_body() - { - area_override_settings = Some(body.get_area_override_settings( - &mut physics_data.spaces, - &physics_data.collision_objects, - )); - } else { - area_override_settings = None; - } - if let Some(area_override_settings) = area_override_settings - && let Some(body) = physics_data.collision_objects.get_mut(&body) - { - if let Some(body) = body.get_mut_body() { - body.apply_area_override( - area_override_settings, - &mut physics_data.physics_engine, - &mut physics_data.spaces, - ); - } - } + for body in &body_area_update_list { + RapierBody::apply_area_orverride_to_body( + body, + &mut physics_data.physics_engine, + &mut physics_data.spaces, + &mut physics_data.collision_objects, + ); } for body in gravity_update_list { if let Some(body) = physics_data.collision_objects.get_mut(&body) @@ -336,7 +321,6 @@ impl RapierSpace { space_handle, &settings, RapierSpace::collision_filter_body_callback, - RapierSpace::collision_filter_sensor_callback, RapierSpace::collision_modify_contacts_callback, space, &mut physics_data.collision_objects, diff --git a/src/spaces/rapier_space_callbacks.rs b/src/spaces/rapier_space_callbacks.rs index d109ec2c..ff93b421 100644 --- a/src/spaces/rapier_space_callbacks.rs +++ b/src/spaces/rapier_space_callbacks.rs @@ -1,7 +1,6 @@ use std::mem::swap; use godot::prelude::*; -use rapier::utils::SimdBasis; use servers::rapier_physics_server_extra::PhysicsCollisionObjects; use super::rapier_space::RapierSpace; @@ -40,35 +39,15 @@ impl RapierSpace { } } - pub fn collision_filter_common_callback( - filter_info: &CollisionFilterInfo, - r_colliders_info: &mut CollidersInfo, - physics_collision_objects: &PhysicsCollisionObjects, - ) -> bool { - (r_colliders_info.object1, r_colliders_info.shape1) = - RapierCollisionObject::get_collider_user_data(&filter_info.user_data1); - (r_colliders_info.object2, r_colliders_info.shape2) = - RapierCollisionObject::get_collider_user_data(&filter_info.user_data2); - if let Some(body1) = physics_collision_objects.get(&r_colliders_info.object1) - && let Some(body2) = physics_collision_objects.get(&r_colliders_info.object2) - { - return body1.get_base().interacts_with(body2.get_base()); - } - false - } - pub fn collision_filter_body_callback( filter_info: &CollisionFilterInfo, physics_collision_objects: &PhysicsCollisionObjects, ) -> bool { let mut colliders_info = CollidersInfo::default(); - if !Self::collision_filter_common_callback( - filter_info, - &mut colliders_info, - physics_collision_objects, - ) { - return false; - } + (colliders_info.object1, colliders_info.shape1) = + RapierCollisionObject::get_collider_user_data(&filter_info.user_data1); + (colliders_info.object2, colliders_info.shape2) = + RapierCollisionObject::get_collider_user_data(&filter_info.user_data2); if let Some(body1) = physics_collision_objects.get(&colliders_info.object1) && let Some(body1) = body1.get_body() && let Some(body2) = physics_collision_objects.get(&colliders_info.object2) @@ -81,18 +60,6 @@ impl RapierSpace { true } - pub fn collision_filter_sensor_callback( - filter_info: &CollisionFilterInfo, - physics_collision_objects: &PhysicsCollisionObjects, - ) -> bool { - let mut colliders_info = CollidersInfo::default(); - Self::collision_filter_common_callback( - filter_info, - &mut colliders_info, - physics_collision_objects, - ) - } - pub fn collision_modify_contacts_callback( filter_info: &CollisionFilterInfo, physics_collision_objects: &PhysicsCollisionObjects, @@ -107,8 +74,7 @@ impl RapierSpace { { let collision_base_1 = collision_object_1.get_base(); let collision_base_2 = collision_object_2.get_base(); - if collision_base_1.interacts_with(collision_base_2) - && !collision_base_1.is_shape_disabled(shape1) + if !collision_base_1.is_shape_disabled(shape1) && !collision_base_2.is_shape_disabled(shape2) { result.body1 = collision_base_1.is_shape_set_as_one_way_collision(shape1); @@ -374,10 +340,8 @@ impl RapierSpace { { let depth = real::max(0.0, -contact_info.pixel_distance); // negative distance means penetration let normal = contact_info.normal; - // TODO calculate impulse for 2d and 3d - let tangent = contact_info.normal.orthonormal_vector(); - let impulse = contact_info.pixel_impulse * normal - + contact_info.pixel_tangent_impulse.x * tangent; + // send just impulse directly along normal + let impulse = contact_info.pixel_impulse * vector_to_godot(normal); let vel_pos1 = contact_info.pixel_velocity_pos_1; let vel_pos2 = contact_info.pixel_velocity_pos_2; if let Some(body1) = p_object1.get_mut_body() { @@ -412,7 +376,7 @@ impl RapierSpace { instance_id2, body2.get_base().get_rid(), vector_to_godot(vel_pos2), - vector_to_godot(impulse), + impulse, ); } if body2.can_report_contacts() { @@ -429,7 +393,7 @@ impl RapierSpace { instance_id1, body1.get_base().get_rid(), vector_to_godot(vel_pos1), - vector_to_godot(impulse), + -impulse, ); } }