✅ add test for ball resting on a horizontal surface
also improved numerical stability in this case by factoring face collisions so a divide happens later.main
parent
96436d6c36
commit
dec16c4079
|
@ -121,11 +121,12 @@ pub fn get_candidate (world: &[Triangle], p0: Vec3, p1: Vec3, radius: f32)
|
|||
let passed_plane = distance_to_face0 > 0.0 && distance_to_face1 < 0.0;
|
||||
|
||||
if passed_plane {
|
||||
let t = distance_to_face0 / (distance_to_face0 - distance_to_face1);
|
||||
let denom = distance_to_face0 - distance_to_face1;
|
||||
let t_times_denom = distance_to_face0;
|
||||
|
||||
// Because of previous early returns we know that 0.0 < t < 1.0
|
||||
|
||||
let p_impact = p0 * (1.0 - t) + p1 * (t);
|
||||
let p_impact_times_denom = p0 * (denom - t_times_denom) + p1 * (t_times_denom);
|
||||
|
||||
let impact_inside_tri = (|| {
|
||||
for j in 0..3 {
|
||||
|
@ -133,7 +134,7 @@ pub fn get_candidate (world: &[Triangle], p0: Vec3, p1: Vec3, radius: f32)
|
|||
let b = tri.verts [(j + 1) % 3];
|
||||
let tangent = Vec3::cross (b - a, normal);
|
||||
|
||||
if Vec3::dot (tangent, p_impact - a) < 0.0 {
|
||||
if Vec3::dot (tangent, p_impact_times_denom - a * denom) < 0.0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -144,8 +145,8 @@ pub fn get_candidate (world: &[Triangle], p0: Vec3, p1: Vec3, radius: f32)
|
|||
// Stop it
|
||||
|
||||
let c = Collision {
|
||||
t,
|
||||
p_impact,
|
||||
t: t_times_denom / denom,
|
||||
p_impact: p_impact_times_denom / denom,
|
||||
normal,
|
||||
i,
|
||||
};
|
||||
|
@ -343,12 +344,6 @@ mod test {
|
|||
fn test_physics () {
|
||||
// Remember, Z is up
|
||||
|
||||
let params = Params {
|
||||
dt: 1.0,
|
||||
gravity: (0.0, 0.0, 0.0).into (),
|
||||
margin: 0.00125,
|
||||
};
|
||||
|
||||
let world: Vec <_> = vec! [
|
||||
(
|
||||
(0.0, 0.0, 0.0),
|
||||
|
@ -367,6 +362,12 @@ mod test {
|
|||
})
|
||||
.collect ();
|
||||
|
||||
let params = Params {
|
||||
dt: 1.0,
|
||||
gravity: (0.0, 0.0, 0.0).into (),
|
||||
margin: 0.00125,
|
||||
};
|
||||
|
||||
let magic_0 = f32::sqrt (f32::powf (0.5 + params.margin, 2.0) / 2.0);
|
||||
|
||||
for ((radius, body_before), e) in [
|
||||
|
@ -450,5 +451,66 @@ mod test {
|
|||
assert_eq! (a.triangles_hit, e.triangles_hit);
|
||||
assert_eq! (a.kill, e.kill);
|
||||
}
|
||||
|
||||
// With no bounce, a ball should settle on a flat triangle in one
|
||||
// frame and reach a steady state
|
||||
|
||||
let params = Params {
|
||||
dt: 1.0,
|
||||
gravity: (0.0, 0.0, -1.0).into (),
|
||||
margin: 0.00125,
|
||||
};
|
||||
|
||||
let radius = 0.5;
|
||||
let body_before = PhysicsBody {
|
||||
pos: (0.5, 0.5, 2.0).into (),
|
||||
vel: (0.0, 0.0, -4.0).into (),
|
||||
};
|
||||
|
||||
assert_eq! (
|
||||
get_candidate (&world, (0.5, 0.5, 2.0).into (), (0.5, 0.5, -3.0).into (), radius),
|
||||
Collision {
|
||||
t: 0.3,
|
||||
p_impact: (0.5, 0.5, 0.5).into (),
|
||||
normal: (0.0, 0.0, 1.0).into (),
|
||||
i: 0,
|
||||
},
|
||||
);
|
||||
|
||||
let a = physics_step (¶ms, &world, radius, &body_before);
|
||||
|
||||
let e = PhysicsResult {
|
||||
body: PhysicsBody {
|
||||
pos: (0.5, 0.5, 0.5 + params.margin).into (),
|
||||
vel: (0.0, 0.0, 0.0).into (),
|
||||
},
|
||||
triangles_hit: vec! [0],
|
||||
kill: false,
|
||||
};
|
||||
|
||||
// Fixed point should be here
|
||||
// If this test passes, at least a ball can rest on a single horizontal
|
||||
// triangle. If it fails, that means the ball is not resting
|
||||
// (maybe the velocity is non-zero even if the position is stable)
|
||||
// or the ball is going to gain energy and bounce away, or it's going
|
||||
// to slide through the triangle.
|
||||
|
||||
let body_before = PhysicsBody {
|
||||
pos: (0.5, 0.5, 0.5 + params.margin).into (),
|
||||
vel: (0.0, 0.0, 0.0).into (),
|
||||
};
|
||||
|
||||
let a = physics_step (¶ms, &world, radius, &body_before);
|
||||
|
||||
let e = PhysicsResult {
|
||||
body: PhysicsBody {
|
||||
pos: (0.5, 0.5, 0.5 + params.margin).into (),
|
||||
vel: (0.0, 0.0, 0.0).into (),
|
||||
},
|
||||
triangles_hit: vec! [0],
|
||||
kill: false,
|
||||
};
|
||||
|
||||
assert_eq! (a, e);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue