Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rapier context as a Component #545

Merged
merged 36 commits into from
Sep 9, 2024
Merged

Conversation

Vrixyz
Copy link
Contributor

@Vrixyz Vrixyz commented Jun 27, 2024

Alternative to support multiple worlds: #328 + lays out the foundation to split RapierContext in multiple elements #502, still grouped in an entity.

  • By using SystemParams for a DefaultRapierContext, the migration for most users is painless.
  • Users developing libraries should go through a more involved migration by supporting multiple worlds.
Solved blockers

Fixed by #563

These crashes have been observed, analysis within Vrixyz#26.

Collision panics

Details: Rapier plugin is in PostUpdate schedule, using TimestepMode::Interpolated.

log

thread 'Compute Task Pool (0)' panicked at /home/cornchip/Programming/rust/bevy_rapier/bevy_rapier3d/../src/pipeline/events.rs:71:14:
Internal error: entity not found for collision event.
stack backtrace:
   0: rust_begin_unwind
             at /rustc/524d806c62a82ecc0cf8634b94997ae506f4d6f9/library/std/src/panicking.rs:661:5
   1: core::panicking::panic_fmt
             at /rustc/524d806c62a82ecc0cf8634b94997ae506f4d6f9/library/core/src/panicking.rs:74:14
   2: core::panicking::panic_display
             at /rustc/524d806c62a82ecc0cf8634b94997ae506f4d6f9/library/core/src/panicking.rs:264:5
   3: core::option::expect_failed
             at /rustc/524d806c62a82ecc0cf8634b94997ae506f4d6f9/library/core/src/option.rs:2023:5
   4: core::option::Option<T>::expect
             at /rustc/524d806c62a82ecc0cf8634b94997ae506f4d6f9/library/core/src/option.rs:926:21
   5: bevy_rapier3d::pipeline::events::EventQueue::collider2entity
             at /home/cornchip/Programming/rust/bevy_rapier/bevy_rapier3d/../src/pipeline/events.rs:67:9
   6: <bevy_rapier3d::pipeline::events::EventQueue as rapier3d::pipeline::event_handler::EventHandler>::handle_collision_event
   7: rapier3d::geometry::narrow_phase::NarrowPhase::remove_collider
             at /home/cornchip/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rapier3d-0.21.0/src/geometry/narrow_phase.rs:347:21
   8: rapier3d::geometry::narrow_phase::NarrowPhase::handle_user_changes
             at /home/cornchip/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rapier3d-0.21.0/src/geometry/narrow_phase.rs:302:17
   9: rapier3d::pipeline::physics_pipeline::PhysicsPipeline::detect_collisions
             at /home/cornchip/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rapier3d-0.21.0/src/pipeline/physics_pipeline.rs:129:13
  10: rapier3d::pipeline::physics_pipeline::PhysicsPipeline::step
             at /home/cornchip/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rapier3d-0.21.0/src/pipeline/physics_pipeline.rs:478:9
  11: bevy_rapier3d::plugin::context::RapierContext::step_simulation
             at /home/cornchip/Programming/rust/bevy_rapier/bevy_rapier3d/../src/plugin/context/mod.rs:292:25
  12: bevy_rapier3d::plugin::systems::step_simulation
             at /home/cornchip/Programming/rust/bevy_rapier/bevy_rapier3d/../src/plugin/systems/mod.rs:51:13
  13: core::ops::function::FnMut::call_mut
             at /rustc/524d806c62a82ecc0cf8634b94997ae506f4d6f9/library/core/src/ops/function.rs:166:5
  14: core::ops::function::impls::<impl core::ops::function::FnMut<A> for &mut F>::call_mut
             at /rustc/524d806c62a82ecc0cf8634b94997ae506f4d6f9/library/core/src/ops/function.rs:294:13
  15: <Func as bevy_ecs::system::function_system::SystemParamFunction<fn(F0,F1,F2,F3,F4,F5,F6) .> Out>>::run::call_inner
             at /home/cornchip/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_ecs-0.14.0/src/system/function_system.rs:710:21
  16: <Func as bevy_ecs::system::function_system::SystemParamFunction<fn(F0,F1,F2,F3,F4,F5,F6) .> Out>>::run
             at /home/cornchip/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_ecs-0.14.0/src/system/function_system.rs:713:17
  17: <bevy_ecs::system::function_system::FunctionSystem<Marker,F> as bevy_ecs::system::system::System>::run_unsafe
             at /home/cornchip/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_ecs-0.14.0/src/system/function_system.rs:534:19
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Encountered a panic in system `bevy_rapier3d::plugin::systems::step_simulation<cosmos_core::physics::collision_handling::CosmosPhysicsFilter>`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!

Different occurence

thread 'Compute Task Pool (1)' panicked at /home/cornchip/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rapier3d-0.21.0/src/dynamics/solver/interaction_groups.rs:440:60:
index out of bounds: the len is 1 but the index is 2
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `bevy_rapier3d::plugin::systems::step_simulation<cosmos_core::physics::collision_handling::CosmosPhysicsFilter>`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!


Strengths

  • rather low impact on existing users, check the examples.
  • using a RapierContext as component avoids maintaining our own indices for worlds, and groups up the dependencies of a RapierContext in the same entity. I believe it will be most helpful when ECS relations will be a thing.

Weaknesses

  • ⚠️ “unwrap” heavy code, relying on those components being added correctly: (bevy relations please 🥺🌈) ; most should probably be if let else.
    • RapierContextEntityLink on every rapier entities
      • Rigidbodies
      • joints
      • Colliders
      • Others ?
  • The root “physics object (linked to by RapierContextEntityLink) ; should always have:
    • RapierContext -> its acces is simplified with RapierContextAccess
    • RapierConfiguration -> as its usage is more advanced, I think it's fine to keep it in queries.
    • RenderToSimulationTime -> same as RapierConfiguration
    • Maybe I’ve forgotten some..?
  • ⚠️ performance: Configuration::physics_pipeline_active being in the RapierContext entity leads to iteration to all entities for each worlds even though it’s not necessary 🙁 (writeback for example)
    • I imagine performance when disabled is not what we should thrive to optimize, but still a pity.
  • ⚠️ Change detection, tracking all these accesses to RapierContext is not trivial, and we should evaluate regressions.
    For now all systems share all these things, which I consider low priority to specialize for each RapierContext (them being components would be interesting but not trivial):
    • Their schedule
    • The timestep mode
    • The physics hook
    • DebugRenderContext
      • might be easy to migrate to a component ; it does involve a pipeline creation though.
      • So probably keep the pipeline as a resource, but have the enabled flag as a component on each RapierContext.
  • Testbed uses DefaultRapierContextAccess, I think that’s OK.
  • there's not a tremendous amount of tests, I noticed I broke events very stealthily so I added a regression test Added 'realistic' test for events #544

Performance analysis

Overall, This pull request doesn't seem to impact significantly the performance based on selected benchmarks:

Comparison with adapted benchmark with baseline from: #551 :

Cubes "master"

     Running benches\cubes.rs (C:\Users\thier\Documents\cargo_target_dir\release\deps\cubes-c309aaa524b91fbb.exe)
Timer precision: 100 ns
cubes                     fastest       │ slowest       │ median        │ mean          │ samples │ iters
├─ cubes_10x10__30_steps  207.6 ms      │ 286.1 ms      │ 216.3 ms      │ 218.1 ms      │ 100     │ 100
├─ cubes_3x3_30_steps     5.451 ms      │ 8.012 ms      │ 5.68 ms       │ 5.851 ms      │ 100     │ 100
╰─ cubes_5x5_30_steps     19.01 ms      │ 22.84 ms      │ 19.67 ms      │ 19.98 ms      │ 100     │ 100

Cubes "This PR"

     Running benches\cubes.rs (C:\Users\thier\Documents\cargo_target_dir\release\deps\cubes-c309aaa524b91fbb.exe)
Timer precision: 100 ns
cubes                    fastest       │ slowest       │ median        │ mean          │ samples │ iters
├─ cubes_10x10_30_steps  206.4 ms      │ 234.1 ms      │ 213.5 ms      │ 215.3 ms      │ 100     │ 100
├─ cubes_3x3_30_steps    5.777 ms      │ 7.041 ms      │ 5.98 ms       │ 6.065 ms      │ 100     │ 100
╰─ cubes_5x5_30_steps    19.4 ms       │ 24.01 ms      │ 19.9 ms       │ 20.4 ms       │ 100     │ 100

many_pyramids3 "master"

     Running benches\many_pyramids3.rs (C:\Users\thier\Documents\cargo_target_dir\release\deps\many_pyramids3-22265334d52714c0.exe)
Timer precision: 100 ns
many_pyramids3               fastest       │ slowest       │ median        │ mean          │ samples │ iters
├─ pyramid_1_with_height_2   20.81 ms      │ 21.44 ms      │ 21.32 ms      │ 21.24 ms      │ 5       │ 25
├─ pyramid_1_with_height_20  1.072 s       │ 1.074 s       │ 1.073 s       │ 1.073 s       │ 2       │ 4
╰─ pyramid_2_with_height_20  4.262 s       │ 4.262 s       │ 4.262 s       │ 4.262 s       │ 1       │ 1

many_pyramids3 "This PR"

     Running benches\many_pyramids3.rs (C:\Users\thier\Documents\cargo_target_dir\release\deps\many_pyramids3-22265334d52714c0.exe)
Timer precision: 100 ns
many_pyramids3               fastest       │ slowest       │ median        │ mean          │ samples │ iters
├─ pyramid_1_with_height_2   21.05 ms      │ 21.98 ms      │ 21.26 ms      │ 21.46 ms      │ 5       │ 25
├─ pyramid_1_with_height_20  1.078 s       │ 1.08 s        │ 1.079 s       │ 1.079 s       │ 2       │ 4
╰─ pyramid_2_with_height_20  4.312 s       │ 4.312 s       │ 4.312 s       │ 4.312 s       │ 1       │ 1

custom_benches "master" 59477d9

average total time: 0.023415528 ms
average rapier step time: 0.00576001 ms
average bevy overhead: 0.017655518 ms
total time: 23.47802734375 ms
average total time: 116.73869 ms
average rapier step time: 116.542145 ms
average bevy overhead: 0.19654846 ms
total time: 11673.889404296875 ms

custom_benches "This PR" deb0a06

average total time: 0.023138916 ms
average rapier step time: 0.0056398925 ms
average bevy overhead: 0.017499024 ms
total time: 23.954345703125 ms
average total time: 115.698875 ms
average rapier step time: 115.48543 ms
average bevy overhead: 0.21344757 ms
total time: 11570.1279296875 ms

@Vrixyz Vrixyz marked this pull request as draft June 27, 2024 15:33
src/plugin/systems/multiple_rapier_contexts.rs Outdated Show resolved Hide resolved
src/plugin/systems/remove.rs Outdated Show resolved Hide resolved
src/plugin/systems/remove.rs Outdated Show resolved Hide resolved
src/plugin/systems/remove.rs Outdated Show resolved Hide resolved
src/plugin/systems/writeback.rs Outdated Show resolved Hide resolved
bevy_rapier3d/examples/multi_world3.rs Show resolved Hide resolved
src/plugin/context/mod.rs Show resolved Hide resolved
src/plugin/plugin.rs Outdated Show resolved Hide resolved
src/plugin/systems/mod.rs Show resolved Hide resolved
src/plugin/systems/rigid_body.rs Outdated Show resolved Hide resolved
src/plugin/context/mod.rs Outdated Show resolved Hide resolved
.github/workflows/main.yml Outdated Show resolved Hide resolved
@Vrixyz Vrixyz requested a review from sebcrozet July 4, 2024 13:25
@Vrixyz Vrixyz marked this pull request as ready for review July 4, 2024 13:25
@Vrixyz
Copy link
Contributor Author

Vrixyz commented Jul 4, 2024

I'm reaching a point where I'm confident with the pull request, feedback is most welcome :)

bevy_rapier3d/examples/ray_casting3.rs Outdated Show resolved Hide resolved
src/plugin/context/mod.rs Outdated Show resolved Hide resolved
src/plugin/context/systemparams/rapier_context_access.rs Outdated Show resolved Hide resolved
src/plugin/context/systemparams/rapier_context_access.rs Outdated Show resolved Hide resolved
src/plugin/context/systemparams/rapier_context_access.rs Outdated Show resolved Hide resolved
src/plugin/systems/joint.rs Outdated Show resolved Hide resolved
}
// Verify link is correctly updated for children.
let new_rapier_context = world.spawn(RapierContext::default()).id();
// FIXME: We need to wait 1 frame when creating a world.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still a problem?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I... believe so. I'll try to track down why exactly.

Copy link
Contributor Author

@Vrixyz Vrixyz Jul 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love a test for that specifically ; I'd love to update this test to be able to test exactly a new RapierContext in the same frame, but I'm not sure on where to insert the user systems exactly for that. Last seems wrong.

src/plugin/systems/writeback.rs Outdated Show resolved Hide resolved
src/plugin/systems/rigid_body.rs Show resolved Hide resolved
src/plugin/systems/rigid_body.rs Show resolved Hide resolved
Copy link
Contributor

@AnthonyTornetta AnthonyTornetta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! I'm looking forward to this becoming the standard API!

src/plugin/plugin.rs Outdated Show resolved Hide resolved
@AnthonyTornetta
Copy link
Contributor

Could we add an easier way to change the fields of RapierContext during its initialization (for the single default-world approach)? Currently I have to write a system that at startup changes those fields, but that seems a bit clunky. Maybe provide the RapierContextInitialization enum with more options?

src/plugin/systems/collider.rs Outdated Show resolved Hide resolved
) {
for (entity, new_physics_world) in &q_changed_worlds {
let context = q_context.get(new_physics_world.0);
if new_physics_world.is_added() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This caused errors for me, where the rapier link wasn't propagating down to children. Not sure why this check is here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial mental model was that this function is responsible of reacting to rapier context change ; addition is handled within init_rigid_bodies and similar functions.

You're correct though, the initialization is lacking the children propagation, I'll see what I can do.

I think keeping a similar logic is easier to reason about 🤔, rather than making an big system responsible for both initializing and update to link changes.

bevy_rapier3d/examples/multi_world3.rs Show resolved Hide resolved
pub struct TestMarker;

#[test]
pub fn hierarchy_link_propagation() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole test could be in another PR to explore ; I think that's an interesting approach to fully master the system ordering. @AnthonyTornetta, this is the direction I'm taking to address your feedbacks on state inconsistencies (mainly hierarchy propagation, not currently tested but I'll probably add it in that way).

It's full of println! ; I quite like those because it helps debugging the tests ; and it's captured anyway. I'm glad to refactor this with specific instructions if need be. @sebcrozet for info.

Copy link
Member

@sebcrozet sebcrozet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking great! Thank you @Vrixyz, @AnthonyTornetta and @Aceeri for the work and reviews!

CHANGELOG.md Outdated Show resolved Hide resolved
CHANGELOG.md Outdated
Comment on lines 21 to 22
- `ResMut<mut RapierContext>` -> `DefaultRapierContextAccessMut`
- `Res<RapierContext>` -> `DefaultRapierContextAccess`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a suggestion. Bevy has these Read<> and Write<> structs. Perhaps, to make the API look more idiomatic the access structs could be named as follow?

Suggested change
- `ResMut<mut RapierContext>` -> `DefaultRapierContextAccessMut`
- `Res<RapierContext>` -> `DefaultRapierContextAccess`
- `ResMut<mut RapierContext>` -> `WriteDefaultRapierContext`
- `Res<RapierContext>` -> `ReadDefaultRapierContext`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TL;DR: ok :)

I tend to prefer suffixes to prefix, so when you're searching for a term, the alphabetical order comes better grouped.

That said, my initial naming does a bad job at putting Default first. For this reason, I might prefer a RapierContextDefaultRead ; but that would probably mean renaming DefaultRapierContext to RapierContextDefault, which might sound weird.

For the idiomatic way, I wanted to keep close to Res / ResMut, which is very idiomatic. I believe Read/Write is used for individual components, which is not exaclty the case here. I'm not sure I've seen it in SystemParam. But I'm not sure.

In any way, I don't feel too opinionated about that, so I'll just implement your suggestion 😅.

CHANGELOG.md Outdated Show resolved Hide resolved
src/pipeline/events.rs Outdated Show resolved Hide resolved
src/plugin/context/mod.rs Outdated Show resolved Hide resolved
src/plugin/context/mod.rs Outdated Show resolved Hide resolved
src/plugin/plugin.rs Outdated Show resolved Hide resolved
src/plugin/systems/rigid_body.rs Outdated Show resolved Hide resolved
@Vrixyz
Copy link
Contributor Author

Vrixyz commented Aug 12, 2024

interesting to note differences of system ordering compared to master (from #576)

graphviz

@sebcrozet sebcrozet self-requested a review August 30, 2024 14:31
Copy link
Member

@sebcrozet sebcrozet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking fantastic, thanks!

@Vrixyz Vrixyz merged commit bab3431 into dimforge:master Sep 9, 2024
4 checks passed
jeyum2 added a commit to jeyum2/bevy_rapier that referenced this pull request Sep 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants