rapier icon indicating copy to clipboard operation
rapier copied to clipboard

[Bug?] Contact of circle and polyline at its vertex produces 0 normal

Open ghost opened this issue 3 years ago • 2 comments

Not sure if this is something fixable as I'm not familiar with the math, but (seemingly) when a circle touches a line just at its vertex, a normal of 0 is produced.

In the case of a one-way platform, this can cause spurious collisions on the very ends of a platform when pass-through is supposed to happen.

Edit: I did some further testing and it seems that the circle wasn't even touching the line when this happens. See below ASCII art.

______o Zero normal contact is reported when the circle sits right beside the line, aligned but not touching it.

Here's a minimal test case:

use rapier2d::pipeline::*;
use rapier2d::dynamics::*;
use rapier2d::geometry::*;
use rapier2d::na::*;

fn main() {
    let mut pipeline = PhysicsPipeline::new();
    let gravity = Vector2::new(0.0, 0.0);
    let integration_parameters = IntegrationParameters::default();
    let mut broad_phase = BroadPhase::new();
    let mut narrow_phase = NarrowPhase::new();
    let mut bodies = RigidBodySet::new();
    let mut colliders = ColliderSet::new();
    let mut joints = JointSet::new();
    let mut ccd_solver = CCDSolver::new();

    // Circle
    let body = RigidBodyBuilder::new_dynamic()
        .translation(11.0, 0.0).build(); // Sits beyond the edge of the ground defined below.
    let handle = bodies.insert(body);
    let collider = ColliderBuilder::ball(1.0) 
        .translation(0.0, 1.0)
        .modify_solver_contacts(true)
        .build();
    colliders.insert(collider, handle, &mut bodies);

    // Ground
    let body = RigidBodyBuilder::new_static().build();
    let handle = bodies.insert(body);
    let collider = ColliderBuilder::polyline(vec![
        Point2::new(-10.0, 0.0),
        Point2::new(10.0, 0.0),
    ], None).build();
    colliders.insert(collider, handle, &mut bodies);

    loop {
        pipeline.step(
            &gravity,
            &integration_parameters,
            &mut broad_phase,
            &mut narrow_phase,
            &mut bodies,
            &mut colliders,
            &mut joints,
            &mut ccd_solver,
            &MyHook,
            &(),
        );
    }
}

// Convenience to detect contacts
struct MyHook;
impl PhysicsHooks for MyHook {
    fn active_hooks(&self) -> PhysicsHooksFlags {
        PhysicsHooksFlags::MODIFY_SOLVER_CONTACTS
    }

    fn modify_solver_contacts(&self, context: &mut ContactModificationContext) {
        if context.manifold.local_n1.x == 0.0 && context.manifold.local_n1.y == 0.0 {
            println!("Zero normal!");
        }
    }
}

ghost avatar Apr 05 '21 11:04 ghost

Hi! This is a bug. A zero normal may be returned in the case where the center of the circle is located on the line. But it should not be zero in other cases.

sebcrozet avatar Apr 06 '21 07:04 sebcrozet

Thanks for the reply! It looks like I'll wait for the fix rather than try to terribly hack my code then :)

ghost avatar Apr 06 '21 13:04 ghost