dimforge / ncollide

2 and 3-dimensional collision detection library in Rust.
https://ncollide.org
Apache License 2.0
920 stars 107 forks source link

Penetration queries work only sporadically with compound shapes #209

Open Sushisource opened 6 years ago

Sushisource commented 6 years ago

I have found that penetration queries seem to only sometimes work for compound shapes against compound shapes. I'm not sure what the circumstance is when they do work, but I have at least one test that consistently fails where it should seemingly return a penetration value:

In this test the north wall of the first room overlaps the south wall of the second. The walls are 0.2 thick.

  #[test]
  fn test_compound_penetration() {
    let mut r1 = Room::new_with_centered_door(Point::new(0.0, 0.0), 10.0, 10.0, Direction::North);
    r1.is_compound = true;
    let starter_loc = r1.location();
    let mut compound_rm = Compound::new(vec![(origin(), r1.shape())]);

    let r2 = Room::new_with_centered_door(Point::new(0.0, 10.0), 10.0, 10.15, Direction::North);
    let r2_s = r2.shape();
    let r2_shape: &CollisionRect = r2_s.as_shape().unwrap();
    let penetration = query::contact(&origin(), &compound_rm, &r2.location(), r2_shape,
                                     WALL_THICKNESS);
    assert!(penetration.is_some())
  }

But the test fails.

For how the "Room" is constructed:

impl Collidable for Room {
  fn location(&self) -> Isometry2<Meters> { Isometry2::new(self.center().coords, na::zero()) }
  fn shape(&self) -> Shape2D {
    let shapes = self.walls.iter().map(|&(w, _)| {
      let cr: CollisionRect = w.into();
      // Wall locations need to be represented relative to the center of the room
      let loc = Isometry2::new(w.center().coords - self.center().coords, na::zero());
      (loc, ShapeHandle::new(cr))
    });
    let whole_shape = Compound::new(shapes.collect());
    ShapeHandle::new(whole_shape)
  }
  fn collision_group(&self) -> CollisionGroups { CollGroups::wall_cg() }
  fn coltype(&self) -> CollidableType {
    if self.is_compound { CollidableType::CompoundRoomWall } else { CollidableType::RoomWall }
  }
}

Here is a picture of the rooms where walls are a not-fully-opaque green, so you can see the overlap as a slightly brighter green: screenshot from 2018-06-12 21-36-11

Am I doing something wrong here? Or is this a bug for compound shapes?

sebcrozet commented 6 years ago

This is a bug. Could you provide more details on the exact location and dimensions of the walls for the example that fails? That would help me reproduce the bug.

sebcrozet commented 6 years ago

While fixing #210, I found a bug that may be related to this issue. @Sushisource Could you please check if your examples still fail with ncollide2d v0.16.1 ?

Sushisource commented 6 years ago

@sebcrozet Thanks, I'll give that a shot. Might take me a bit because I'm using ggez for the rendering and they are pointing at older nalgebra still which is causing some compat issues. As soon as they update or I work around them I'll let you know.

Sushisource commented 6 years ago

@sebcrozet Was able to get everything compiling and this is indeed fixed in 0.16.1. Thanks!

I've been trying to use a time-of-impact query to slide two compound shapes together, so they are exactly touching, and then move them one wall-thickness along the normal so the walls overlap completely, but I've not had much success. After re-runing a contact query the penetration depths are always nearly exactly correct, but I'll still end up sometimes with things not quite lining up just right visually.

Would that approach be expected to work? I think I may just switch to an explicit grid for this particular task. Thanks again!

sebcrozet commented 6 years ago

@Sushisource Since ncollide does not implement a dedicated box/box algorithm for distance and penetration depth computation yet, there might be some cases where the generic iterative algorithms don't yield the exact results because of lack of convergence. So you may be experiencing this.

If you can give me a way to reproduce the bug your are experiencing (for example if your code and the steps to reproduce the issue are available somehow), I could take a look and see if there is still a bug somewhere on ncollide.