Skip to content

Commit 23dc1cb

Browse files
committed
[remove] custom solver contact hook and use rapier material configs directly.
1 parent 4d15791 commit 23dc1cb

File tree

1 file changed

+38
-40
lines changed

1 file changed

+38
-40
lines changed

crates/lambda-rs-platform/src/physics/rapier2d.rs

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -169,41 +169,6 @@ struct ColliderAttachmentMassPlan2D {
169169
should_remove_fallback_mass: bool,
170170
}
171171

172-
/// Applies Lambda collision-material combination rules to solver contacts.
173-
///
174-
/// This hook implements backend-agnostic combination semantics without
175-
/// exposing vendor types to `lambda-rs`:
176-
/// - `combined_friction = sqrt(friction_a * friction_b)`
177-
/// - `combined_restitution = max(restitution_a, restitution_b)`
178-
#[derive(Debug, Clone, Copy)]
179-
struct ColliderMaterialCombineHooks2D;
180-
181-
impl PhysicsHooks for ColliderMaterialCombineHooks2D {
182-
fn modify_solver_contacts(&self, context: &mut ContactModificationContext) {
183-
let Some(collider_1) = context.colliders.get(context.collider1) else {
184-
return;
185-
};
186-
let Some(collider_2) = context.colliders.get(context.collider2) else {
187-
return;
188-
};
189-
190-
let friction_1 = collider_1.friction();
191-
let friction_2 = collider_2.friction();
192-
let restitution_1 = collider_1.restitution();
193-
let restitution_2 = collider_2.restitution();
194-
195-
let combined_friction = (friction_1 * friction_2).sqrt();
196-
let combined_restitution = restitution_1.max(restitution_2);
197-
198-
for solver_contact in context.solver_contacts.iter_mut() {
199-
solver_contact.friction = combined_friction;
200-
solver_contact.restitution = combined_restitution;
201-
}
202-
203-
return;
204-
}
205-
}
206-
207172
/// A 2D physics backend powered by `rapier2d`.
208173
///
209174
/// This type is an internal implementation detail used by `lambda-rs`.
@@ -219,7 +184,6 @@ pub struct PhysicsBackend2D {
219184
multibody_joints: MultibodyJointSet,
220185
ccd_solver: CCDSolver,
221186
pipeline: PhysicsPipeline,
222-
material_combine_hooks_2d: ColliderMaterialCombineHooks2D,
223187
rigid_body_slots_2d: Vec<RigidBodySlot2D>,
224188
collider_slots_2d: Vec<ColliderSlot2D>,
225189
}
@@ -253,7 +217,6 @@ impl PhysicsBackend2D {
253217
multibody_joints: MultibodyJointSet::new(),
254218
ccd_solver: CCDSolver::new(),
255219
pipeline: PhysicsPipeline::new(),
256-
material_combine_hooks_2d: ColliderMaterialCombineHooks2D,
257220
rigid_body_slots_2d: Vec::new(),
258221
collider_slots_2d: Vec::new(),
259222
};
@@ -864,7 +827,7 @@ impl PhysicsBackend2D {
864827
&mut self.impulse_joints,
865828
&mut self.multibody_joints,
866829
&mut self.ccd_solver,
867-
&self.material_combine_hooks_2d,
830+
&(),
868831
&(),
869832
);
870833

@@ -1035,6 +998,11 @@ impl PhysicsBackend2D {
1035998
/// inserts the built collider into Rapier, recomputes parent mass
1036999
/// properties, and allocates the public collider slot.
10371000
///
1001+
/// Lambda material semantics are encoded using Rapier's built-in combine
1002+
/// rules instead of a custom contact hook:
1003+
/// - friction stores `sqrt(requested_friction)` and uses `Multiply`
1004+
/// - restitution stores the requested value and uses `Max`
1005+
///
10381006
/// # Arguments
10391007
/// - `parent_slot_index`: The parent rigid body slot index.
10401008
/// - `parent_slot_generation`: The parent slot generation counter.
@@ -1073,9 +1041,10 @@ impl PhysicsBackend2D {
10731041
.translation(Vector::new(local_offset[0], local_offset[1]))
10741042
.rotation(local_rotation)
10751043
.density(rapier_density)
1076-
.friction(friction)
1044+
.friction(encode_rapier_friction_coefficient(friction))
1045+
.friction_combine_rule(CoefficientCombineRule::Multiply)
10771046
.restitution(restitution)
1078-
.active_hooks(ActiveHooks::MODIFY_SOLVER_CONTACTS)
1047+
.restitution_combine_rule(CoefficientCombineRule::Max)
10791048
.build();
10801049

10811050
let rapier_handle = self.colliders.insert_with_parent(
@@ -1433,6 +1402,22 @@ fn resolve_additional_mass_kg(
14331402
return Ok(fallback_mass_kg);
14341403
}
14351404

1405+
/// Encodes a public friction coefficient for Rapier's `Multiply` rule.
1406+
///
1407+
/// Lambda specifies `sqrt(friction_a * friction_b)` as the effective contact
1408+
/// friction. Rapier cannot express that rule directly, so the backend stores
1409+
/// `sqrt(requested_friction)` on each collider and relies on
1410+
/// `CoefficientCombineRule::Multiply` to recover the public result.
1411+
///
1412+
/// # Arguments
1413+
/// - `requested_friction`: The public friction coefficient.
1414+
///
1415+
/// # Returns
1416+
/// Returns the Rapier friction coefficient to store on the collider.
1417+
fn encode_rapier_friction_coefficient(requested_friction: f32) -> f32 {
1418+
return requested_friction.sqrt();
1419+
}
1420+
14361421
/// Resolves how attaching a collider affects a body's backend mass state.
14371422
///
14381423
/// This helper encodes the public density semantics without directly mutating
@@ -1735,6 +1720,19 @@ mod tests {
17351720
return;
17361721
}
17371722

1723+
/// Encodes friction so Rapier `Multiply` matches the public rule.
1724+
#[test]
1725+
fn rapier_friction_encoding_preserves_public_combination_semantics() {
1726+
let encoded_friction_1 = encode_rapier_friction_coefficient(4.0);
1727+
let encoded_friction_2 = encode_rapier_friction_coefficient(9.0);
1728+
1729+
assert_eq!(encoded_friction_1, 2.0);
1730+
assert_eq!(encoded_friction_2, 3.0);
1731+
assert_eq!(encoded_friction_1 * encoded_friction_2, 6.0);
1732+
1733+
return;
1734+
}
1735+
17381736
/// Verifies that applying an impulse updates velocity immediately.
17391737
#[test]
17401738
fn impulse_updates_velocity_immediately() {

0 commit comments

Comments
 (0)