jcornaz / heron

[DISCONTINUED] An ergonomic physics API for bevy games
MIT License
292 stars 44 forks source link

RigidBodies clip/sink into static geometry at slightly high speeds #276

Closed Gonkalbell closed 2 years ago

Gonkalbell commented 2 years ago

I first noticed this issue in bevy_ecs_ldtk's platformer example, where the player clips through the ground and slowly rises back up:

Screencast from 06-05-2022 07 48 48 PM

It looks like I can repro the same issue in this crate's examples as well. Here I just added a wall to the events example, and tried running into it. The problem is noticeable with the default const SPEED: f32 = 300.0;, but changing the speed to something higher like 600 makes it much easier to see:

Screencast from 06-05-2022 07 59 21 PM

My guess is it's just an issue with the default values for PhysicsSteps, or perhaps something like IntegrationParameters::max_position_iterations is to small by default.

jcornaz commented 2 years ago

Isn't that rapier's behavior?

Gonkalbell commented 2 years ago

It may be. I tried reproing this in rapier_2d's examples. I believe I did still see some clipping, but it wasn't quite as extreme. Maybe there's a difference in the default settings? I could open an issue in reapier's repo, though, if that's where you believe the bug is.

jcornaz commented 2 years ago

I am not sure it is even a bug at all. I think it is rapier's intended behavior.

But that behavior is likely to be impacted by the step rate and whether ccd is enabled.

May I ask what is your FPS? And maybe can you try with CCD enabled?

Gonkalbell commented 2 years ago

FrameTimeDiagnosticsPlugin is reporting a consistent 60fps. I think the screen captures I took were at a lower framerate, so that's why the gifs I posted look janky.

I tried out enabling CCD, but that didn't seem to help. I also tried setting IntegrationParameters::max_position_iterations to something like 4 or 8. There still seemed to be some collider penetration, but it didn't seem to take as many frames to exit the other collider.

You're probably right that this is just an issue in rapier. Rapier's changlog seems to mention changes to integration calculation and resolving collider penetration in versions 0.12 and 0.13, so I'll check if it's resolved upstream.

jcornaz commented 2 years ago

Ok. Thanks for the info.

I do plan to update the version of rapier used by heron. But I would like to batch that update with the next update of bevy so that I don't break the API the rapier update.

Though, if updating rapier does fix that kind of problem, I may consider updating it before the next bevy release comes out.

jcornaz commented 2 years ago

@Gonkalbell heron 4.0.0-alpha.1 is using rapier 0.13.0. Can you try with that version and tell me if the problem persists?

bit-garden commented 2 years ago

Tldr; Mathmatically speaking, your objects are too big and more gravity doesn't fix it.

Lower the gravity and use smaller objects to fix the simulation, then scale up your rendering to look right on the sceen. (PS, Bevy_rapier has a solution for this.)


The speeds are supposed to be in meters. But Bevy_rapier provides a way to set a pixel to meter ratio.

In my initial attempts to use Heron, I had a dynamic ball at 0, 0 and a static block at 0, -200 with gravity at 0, -9.8. The simulation appeared slow and the ball would slowly correct itself on impact. I don't see a scaling option currently and Heron looks to treat a pixel as a meter.

I did the same setup in Bevy_rapier and it yields more expected results of stopping on impact instead of falling into the block.

  commands
    .spawn()
    .insert(Collider::cuboid(500.0, 50.0))
    .insert_bundle(TransformBundle::from(Transform::from_xyz(0.0, -200.0, 0.0)));

  /* Create the bouncing ball. */
  commands
    .spawn()
    .insert(RigidBody::Dynamic)
    .insert(Collider::ball(50.0))
    .insert(Restitution::coefficient(0.7))
    .insert_bundle(TransformBundle::from(Transform::from_xyz(0.0, 0.0, 0.0)));

This also indicates that the bevy_ecs_ldtk's platformer example is not working with trivial amounts of gravity.

.insert_resource(Gravity::from(Vec3::new(0.0, -2000., 0.0)))

accelerating 2000 meters(4473 miles per hour) per second is a lot.

Reference: Common mistakes

The recommended way of using Rapier is to use SI units (meters, seconds, kilograms, etc.) If the player sprite is a 100x100 cuboid, then it is as if your player is 100 meters tall and 100 meters wide, which is huge. Therefore it is recommended ot have a scaling factor between the graphics and the physics. For example we can say that 1 physics meter is equal to 50 pixels. This means that we can initialize our player collider as a 2x2 cuboid while still using a 100x100 pixels sprite.

In this example, we could set RapierPhysicsPlugin::pixels_per_meter(50.0) so that while all the transforms, collider size, positions, etc. are expressed in pixels on your end, bevy_rapier will automatically divide them by 50.0 whenever it inputs/reads data into/from Rapier itself.

jcornaz commented 2 years ago

Yes, that's right. Thanks @bit-garden for pointing this out.

I am closing this issue in favor of #284