dimforge / rapier

2D and 3D physics engines focused on performance.
https://rapier.rs
Apache License 2.0
3.93k stars 244 forks source link

KinematicCharacterController movement with surface normal corrections #426

Closed HugoPeters1024 closed 1 year ago

HugoPeters1024 commented 1 year ago

One tedious issue that I encounter with the KinematicCharacterController (in both 2d and 3d) is that when I press my character against an object sideways, it no longer slides down, even though it is part of the translation. Ideally the velocity is clamped against the normal of surface it collides with.

Or perhaps I am using the api wrong?

lzurbriggen commented 1 year ago

This is also a major blocker for me, so I went ahead and tried to implement/fix it. I was somewhat successful.

I created a more basic version of the controller that works for me. You can take a look at my fork. The only real changes were in the cast_shape section of move_shape. In essence it's just this portion:

// We hit something, compute the allowed self.
let allowed_dist =
    (toi.toi - (-toi.normal1.dot(&translation_dir)) * offset).max(0.0);
let allowed_translation = *translation_dir * allowed_dist;

result.translation += allowed_translation;

let unapplied_translation = translation_remaining - allowed_translation;

// ... (there's some more code here to prevent sliding on shallow slopes)

// project translation onto plane to slide along it
translation_remaining = unapplied_translation
        - toi.normal1.scale(unapplied_translation.dot(&toi.normal1));

Unfortunately this broke most of the advanced features of the controller (autostep, unclimbable slopes, collision impulses). I haven't looked at that stuff (yet) so I removed them for now. That's also why I can't really open a PR for this.

I really hope we can get this behavior in KinematicCharacterController.

Related: dimforge/bevy_rapier/issues/301

janhohenheim commented 1 year ago

After working on it a little bit, I can also report that most tries to fix this eliminate the slope and stair features. Parts of the movement logic happen in the handle_slopes and handle_stairs. If the part before, which handles the movement on collisions, is changed to slide along obstacles, it "steals" translation_remaining from the aforementioned functions, which cannot do their job anymore. This is unfortunate, since to me it seems that the following part must be changed:

let allowed_dist = (toi.toi - (-toi.normal1.dot(&translation_dir)) * offset).max(0.0);
let allowed_translation = *translation_dir * allowed_dist;

This ignores the fact that the individual axis of translation_dir should have different allowed distances!

The next person working on this might profit from https://github.com/dimforge/rapier/pull/443. I added a wall on the right side of the 2D character controller example that you can press against to test the behavior after changes.

janhohenheim commented 1 year ago

Update: Managed to fix it in #446 after all by going along obstacle after the slope and stair checks :D