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

Rebrand to Avian #397

Merged
merged 33 commits into from
Jul 5, 2024
Merged

Rebrand to Avian #397

merged 33 commits into from
Jul 5, 2024

Conversation

Jondolf
Copy link
Owner

@Jondolf Jondolf commented Jul 5, 2024

Closes #346.

The avian branch has been used for developing a lot of the features for the next evolution of Bevy XPBD, Avian Physics. This PR merges the numerous improvements and reworks to main, completing the rebrand. See #346 for background.

Note that some other changes were already merged to main in separate PRs.

After this is merged, I will:

  • Rename the repository to "avian"
  • Do a quick final pass to make sure there are no obvious issues or regressions
  • If everything is fine, release avian2d and avian3d
  • Add release notes and a migration guide here on GitHub (I have them ready to go)
  • Post a more in-depth blog post on my website (I have it ready to go)
  • Post about the release on Discord and Reddit

Jondolf and others added 30 commits June 14, 2024 13:08
# Objective

*Note: This PR targets the `avian` branch instead of `main`. This is intended, as this is a part of an ongoing rework.*

The current module structure is not ideal.

![Old module structure](https://github.com/Jondolf/bevy_xpbd/assets/57632562/05f809fc-e9fd-4358-8b19-5947fe780357)

- `components` just contains a bunch of components with no clear separation of concerns, and some components are still stored elsewhere, so it's not even comprehensive at all.
- `resources` has the same issue; no separation of concerns, and it's pretty random which resources are there vs. elsewhere.
- Why is `constraints` a top-level module? It's mainly a solver implementation detail.
- `plugins` is weird, because it has sub-folders with sub-plugins, and really it's just a folder for basically all functionality in the engine.

The lack of separation of concerns harms the modularity of the engine and can make it harder to find things. For a project at this scale, modules like `components` are bad.

## Solution

- Yeet `plugins`, `components`, and `resources`, flatten the module structure.
- Organize everything by logical concerns.
  - Components and resources related to colliders and collision detection are in `collision`.
  - Components and resources related to rigid bodies, gravity, and so on are in `dynamics`
  - Resources related to scheduling are in `schedule`.
- Add `dynamics` module for encapsulating rigid body dynamics (solver, sleeping, rigid body components, etc.), which also gives a nice place for more high-level docs.

![New module structure](https://github.com/Jondolf/bevy_xpbd/assets/57632562/c8e21df4-5634-4174-81c5-6d2b1349005a)

This PR also contains some other miscallaneous improvements:

- Split the `PhysicsSetupPlugin` into `PhysicsSchedulePlugin` and `PhysicsTypeRegistrationPlugin`
- Fixed broken doc links.
- Generally improved some docs.
- Improved the `Rotation` type, making it closer match Bevy's new `Rot2`.
  - This is very unrelated, but it's a part of the ongoing rework anyway and annoying to split out :P

---

## Migration Guide

- The internal module structure has changed significantly, and types have moved around. Most imports from the `prelude` should work like before, but explicit import paths may be broken.
- The `PhysicsSetupPlugin` has been split into `PhysicsSchedulePlugin` and `PhysicsTypeRegistrationPlugin`.
…collision (#385)

# Objective

*Note: This is for the `avian` branch, which will later be pushed to `main`.*

Bevy XPBD currently uses Extended Position-Based Dynamics for its solver. While it has worked quite well, it does have several issues:

- Solving deep overlap is very energetic and explosive.
- Position-based constraints often have high-frequency oscillation where bodies are always slightly moving back-and-forth. XPBD rarely (if ever) reaches a truly stable and relaxed state without sleeping.
- A ton of substeps are needed for minimizing jitter and making systems of bodies stable.
- Friction is typically not quite as robust as it is with impulse-based methods. There are several ways of handling it, some better than others, but it can still have some issues.
- Many features can be more challenging to implement and expose APIs for, and there are fewer learning resources and references for the usage of XPBD in game physics.

Additionally, XPBD even has some potential legal ambiguities, see #346.

Aside from XPBD itself, there are also several other issues with the current collisions and rigid body dynamics:

- Narrow phase collision detection is run at every substep instead of just once per frame like most physics engines. This can be very bad for performance.
- There is no support for any kind of Continuous Collision Detection, so tunneling can be a big issue.
- It is not possible to configure the behavior of collisions aside from the number of substeps.
- #224
- Sleeping in 0.4 just doesn't work.

These are big issues, and I don't currently see XPBD as the best option for the contact solver going forward. Extensive rewrites and fixes are needed.

## Solution

This PR consists of three major parts:

- Rewrite the contact solver to use an impulse-based TGS Soft solver instead of XPBD.
- Rework the narrow phase and other collision detection logic.
- Implement speculative collision, a form of Continuous Collision Detection.

They all relate to each other, and are covered in detail below.

### Substepped Impulse-Based Solver With Soft Constraints

The contact solver has been rewritten to use **TGS Soft**, a substepped impulse-based solver using soft constraints. The choice was largely motivated by the wonderful Erin Catto's [Solver2D] experiments, where TGS Soft was deemed as quite a clear winner.

Box2D V3 was used as the primary inspiration for the core implementation of the new solver. Engines such as Rapier and Bepu also use a very similar approach.

#### Terminology

- **Projected Gauss-Seidel (PGS)**: The classic iterative approach to solving constraints (contacts and joints) using the [Gauss-Seidel](https://en.wikipedia.org/wiki/Gauss%E2%80%93Seidel_method) numerical method. Reframed by Erin Catto as [Sequential Impulses](https://box2d.org/files/ErinCatto_SequentialImpulses_GDC2006.pdf).
- **Temporal Gauss-Seidel (TGS)**: Same as PGS, but prefers *substepping* over *iteration*, running more simulation steps with smaller time steps rather than simply iteratively solving constraints. Substeps tend to be more effective than iterations, as shown in the [Small Steps in Physics Simulation](https://mmacklin.com/smallsteps.pdf) paper by Macklin et al.
- **Baumgarte stabilization**: When solving contact constraints using impulses, boost the impulses using a **bias** to account for overlap and actually push the bodies apart.
- **Soft constraints**: Similar to Baumgarte stabilization, but more stable and controlled. Based on the [harmonic oscillator](https://en.wikipedia.org/wiki/Harmonic_oscillator), soft constraints dampen constraint responses, and can be tuned intuitively with a frequency and damping ratio.
- **Warm starting**: Store the constraint impulses from the previous frame and initialize the solver by applying them at the start of the current frame. This helps the solver converge on the solution faster, and is especially helpful when objects are coming to rest.
- **Relaxation**: Baumgarte stabilization and soft constraints can add unwanted energy. Relaxation helps remove it by solving constraints a second time, but without a bias.

Please refer to the [Solver2D] post for a more complete overview of what TGS and soft constraints are, how they work, and how they relate to other approaches.

#### Solver Overview

As stated earlier, contacts use TGS Soft. However, joints still currently use XPBD, so the new solver is actually a kind of hybrid solver. I do plan on transitioning joints away from XPBD in the future though.

Below is a high-level overview of the new structure of the solver.

1. Broad phase collision detection collects potential collision pairs into `BroadCollisionPairs`.
2. Narrow phase collision detection computes contacts for the pairs and adds them to `Collisions`.
3. A `ContactConstraint` is generated for each contact manifold, and added to `ContactConstraints`.
4. Substepping loop, running `SubstepCount` times.
	1. Integrate velocities, applying gravity and external forces.
	2. Warm start the solver.
	3. Solve velocity constraints with bias (soft constraints).
	4. Integrate positions, moving bodies based on their velocities.
	5. Relax velocities by solving constraints again, but *without* bias.
	6. Solve XPBD constraints (joints) and perform XPBD velocity projection.
5. Apply restitution as a post-phase.
6. Finalize positions by applying `AccumulatedTranslation`.
7. Store contact impulses for next frame's warm starting.

Refer to the code for implementation details. The contact logic and constraints are quite heavily commented and should hopefully be relatively easy to follow.

#### New Solver Results

Collisions have significantly less drift than before, and performance is much better. Below is a pyramid with a base of 64 boxes, simulated with 4 substeps, with sleeping disabled.

**Old**: XPBD has substantial drift, and the pyramid quickly collapses in on itself. This even happens with a much larger number of substeps, although to a slightly lesser degree. Performance is very poor, even with just 4 substeps. 

https://github.com/Jondolf/bevy_xpbd/assets/57632562/ca0ff2f5-dfad-4395-a662-be41cdd7bfcf

**New**: With TGS Soft, the pyramid stays stable. There is a very small amount of drift over a long period of time, but even that can be mitigated by configuring the contact behavior through the `SolverConfig` and/or by adding more substeps.

https://github.com/Jondolf/bevy_xpbd/assets/57632562/a4a48e95-d8e9-459e-bfbb-26d0d12bb8ac

Impulses even out and stabilize *much* better with TGS Soft, even with deep overlap. In overlapping cases, the old XPBD implementation was significantly more explosive. Below is an example where colliders are dynamically enlarged to fill up a container.

**Old**: With XPBD, overlap causes explosions even before the shapes fill the container. Once they do fill the container, they jitter very strongly and explode through the walls. This is typically very undesirable for games.

https://github.com/Jondolf/bevy_xpbd/assets/57632562/e2d47c7e-b03a-45a7-93f9-8c5909564af0

**New**: Overlap is solved perfectly smoothly with no explosions. The contact impulses even out without jitter. With no space to go, the shapes prioritize stability over perfectly hard contacts that would cause explosiveness.

https://github.com/Jondolf/bevy_xpbd/assets/57632562/78f3d158-42a1-4841-b68d-3a6e3e06e451

An important thing to note is that the new solver uses several tolerances and thresholds that are length-based. The old solver also had some tolerances, but now they are much more important for stability.

Without any tuning, a 2D game using pixels as length units might have collision issues, because the tolerances would be wrong for that application. For example, below is a scene with stacks of balls that have a radius of 5.0, with no tuning whatsoever:

![No tuning](https://github.com/Jondolf/bevy_xpbd/assets/57632562/1e548a85-85ba-4811-9a92-b91ca8142927)

The contacts are too soft. To fix this, there is a new `PhysicsLengthUnit` resource, which can be thought of as a kind of pixels-per-meter conversion factor. It is only for scaling the internal tolerances (and debug rendering gizmos!) however, and doesn't scale objects or velocities in any way.

`PhysicsLengthUnit` can be easily set when adding `PhysicsPlugins` for an app:

```rust
fn main() {
    App::new()
        .add_plugins((
            DefaultPlugins,
            // A 2D game with 20 pixels per meter
            PhysicsPlugins::default().with_length_unit(20.0),
        ))
        .run();
}
```

And with that, we get the stability and behavior we expect:

![With the appropriate length unit](https://github.com/Jondolf/bevy_xpbd/assets/57632562/1a64fef5-539d-450d-96da-43fdbaceb430)

[Solver2D]: https://box2d.org/posts/2024/02/solver2d/

### Collision Detection Refactor

The narrow phase and the `PostProcessCollisions` schedule are now run in the `PhysicsSchedule` instead of the `SubstepSchedule`. This greatly improves performance, and also makes collision events and reacting to collisions less awkward and footgunny: previously, the contact data was always from the *last* substep, but at that point, the contact is often already mostly resolved.

Moving narrow phase collision detection out of the substepping loop is possible by simply storing contact data in local space and computing the updated separation distance at each substep using the current poses of the bodies. This way, the contact data is (approximately) accurate even with the bodies moving relative to each other within substeps.

A few other improvements have been made as well:

- The narrow phase logic has been extracted into a `NarrowPhase` system parameter.
- The broad phase now outputs intersection pairs with the entities in ascending order instead of based on the minimum X extent. This fixes issues where bodies moving past each other on the X axis counts as a separate collision, causing problems with collision events.
- #224 is fixed.
- The warnings logged for overlapping bodies have less false alarms.

### Speculative Collision

Tunneling is a phenomenon where fast-moving small objects can pass through thin geometry such as walls due to collision detection being run at discrete time steps:

![Tunneling](https://github.com/Jondolf/bevy_xpbd/assets/57632562/a7b6af19-caf1-4c72-9747-aa834e452e47)

Moving the narrow phase out of the substepping loop has the unfortunate consequence that it increases the risk of tunneling as collisions are not computed as frequently. A solution for this is needed before we commit to the narrow phase change.

One of the primary solutions to tunneling is **Continuous Collision Detection**. There are two common forms:

1. **Sweep-based CCD**: Each collider with CCD enabled is swept from the current position to the predicted one (or from the previous position to the current one). If a hit is detected, the bodies are moved to the time of impact. Contact resolution can be left to the next frame, or to avoid "time loss", performed immediately with a substepping scheme that can also consider secondary collisions.
2. **Speculative CCD**: Contact points are predicted by the narrow phase for fast-moving objects before they actually touch. Speculative collision response is handled by pushing back the part of velocity that would cause penetration.

Sweep-based CCD can be much more expensive and more complex, especially with substepping and non-linear sweeps. Speculative collision on the other hand is very cheap while still being quite robust, although in rare cases it can miss collisions or cause ghost collisions.

The new solver implements speculative collision, which is enabled for *all* bodies *by default*. In my experiments, this is efficient, improves stability, and eliminates almost *all* tunneling except when caused by contact softness. This approach seems to also be taken by both Bepu and Box2D.

Below is a high-level overview of how speculative collision is currently implemented.

- The speculative margin is the maximum distance at which a collision pair generates speculative contacts. This is unbounded for every rigid body by default, which eliminates almost all tunneling.
- Each AABB is expanded in the movement direction based on the body's velocity, clamped by the speculative margin if it is bounded. (Box2D might have a way to avoid this expansion, but I haven't looked into it yet)
- The effective speculative margin is the actual margin used for contact computation, and it is clamped based on the velocities. This is used as the maximum separation distance for contact / closest point computation.
- When actually solving the contact (normal part, no friction), use the softness parameters only if the contact is penetrating. Otherwise it is speculative, and we bias the impulse to cancel out the velocity that would cause penetration.
- Apply restitution in a separate phase after the substepping loop.

![Speculative collision](https://github.com/Jondolf/bevy_xpbd/assets/57632562/ba895617-4ee9-4a36-bc42-b5b6ebacac11)

From a user's point of view, this happens completely in the background. However, if desired, the speculative margin can be configured for an entity using the `SpeculativeMargin` component, or even globally using `default_speculative_margin` in `NarrowPhaseConfig`.

Below is an example of balls being shot at high speeds at thin walls and spinning objects, with just a single substep to eliminate the effect of substepping. The simulation is paused and stepped manually a few times to closer see the behavior.

**Old**: Almost all of the balls simply pass through the thin geometry. With more substeps, this tunneling could been reduced, but never removed completely. Increasing the substep count would also hurt performance.

https://github.com/Jondolf/bevy_xpbd/assets/57632562/03f9f623-0c5f-4228-a913-29bfaad23dc4

**New**: The balls never tunnel straight through the walls, and often even hit the spinning objects. You can still see many balls phasing through the walls, but this is mostly due to contact softness, in cases where a body hits another body hard enough to force it through the wall.

https://github.com/Jondolf/bevy_xpbd/assets/57632562/70526783-762a-452c-87fd-fe23789560f9

Of course, bodies getting pushed through the ground by other bodies is still an issue. This could be reduced in the future by solving contacts against static objects *after* dynamic-dynamic contacts, giving them higher priority and stiffness. This is follow-up material however, and cases where this is an issue should be quite rare in games.

Sweep-based CCD will also be added as an option in a follow-up. I already have an implementation ready locally.

## Performance Results

Comparing this branch to the `avian` branch (which still has the old solver), there is a roughly 4-5x performance improvement for collision-heavy scenes, with the difference growing with the number of collisions and the number of substeps.

The benchmarks below use 8 substeps.

![Benchmark with 8 substep](https://github.com/Jondolf/bevy_xpbd/assets/57632562/a369b674-5710-4c85-85ef-60e5585dafd7)

With just a single substep, the difference is smaller, but this branch is still faster, up to 2x.

![Benchmark with 1 substep](https://github.com/Jondolf/bevy_xpbd/assets/57632562/a753902b-99f4-4d5b-bfcc-a1852ae8cf3c)

## Other Changes

This is such a big rework that it is unfortunately almost impossible to cover every change. Below are some noteworthy changes however.

### Sleeping Rework

- Sleeping in 0.4 was broken, and bodies never fell asleep properly. This has been fixed.
- Bodies now store a `PhysicsChangeTicks` component. This is used to detect what component changes are made by the user *outside* of physics schedules, and what changes are made by the physics engine. This way, we can ignore changes made by the physics engine and have more control over when bodies are woken up.
- For now, bodies can only sleep when they are not in contact with other dynamic bodies. This is because the current per-body sleeping approach is quite buggy and has stability issues. In the future, I plan on implementing simulation islands and doing per-island sleeping like most other physics engines.

### Integrator Rework

- Velocity integration and position integration now run in separate systems and in different parts of the schedule: `IntegrationSet::Velocity` and `IntegrationSet::Position`. This is needed for the new solver.
- The semi-implicit Euler integration scheme now has its own module with proper docs and tests.
- Integration uses `par_iter_mut`.

### Scheduling Changes

- `PhysicsStepSet` now has `First` and `Last` variants, so users can easily schedule systems before or after physics in the `PhysicsSchedule`.
- The narrow phase and the `PostProcessCollisions` schedule are now run in `PhysicsStepSet::NarrowPhase` instead of `SubstepSet::NarrowPhase`.
- Integration is now run in `IntegrationSet::Velocity` and `IntegrationSet::Position` instead of `SubstepSet::Integrate`.
- `SubstepSet` has been removed.
	- The solver runs in `PhysicsStepSet::Solver`.
	- The solver's system sets are in `SolverSet`.
	- Substepping is performed in `SolverSet::Substep`.
	- The substepping loop's system sets are in `SubstepSolverSet`.

### New Configuration Options

- `NarrowPhaseConfig` has new `default_speculative_margin` and `contact_tolerance` properties.
- The new `SolverConfig` resource can be used for tuning collisions.
- The new `PhysicsLengthUnit` resource can be used as a scaling factor for internal length-based tolrances.
	- Existing length-based tolerances and thresholds are now scaled by this, like the `linear` property of `SleepThreshold`.
	- Debug rendering is also scaled by the length unit.

### Examples

- `XpbdExamplePlugin` has been renamed to `ExampleCommonPlugin`, and it no longer adds `PhysicsPlugins` automatically.
- 2D examples have `PhysicsLengthUnit` configured.
- The `one_way_platform` example's logic has been modified to account for `PostProcessCollisions` no longer running in the `SubstepSchedule`.
- The collision logic for the kinematic character controller examples has been rewritten to run in the `PhysicsSchedule` without jitter or stability issues.

### Miscallaneous

- `ColliderAabb` now has the `grow` and `shrink` methods.
- `ContactData` now stores feature IDs for contact matching, which is needed for warm starting.
- `ContactData` property `index` has been removed.
- 3D tangent impulses are now 2D vectors instead of scalar values.

---

## Migration Guide

### New Contact Solver

The contact solver has been rewritten. In practice, this has the following effects:

- Collisions should be much more stable.
- Resolving overlap is no longer nearly as explosive.
- Less substeps are generally needed for stability.
- Tunneling is much more rare.
- Performance is better.

However:

- Contacts may even be *too* soft by default for some applications. This can be tuned with the `SolverConfig`.
- Static friction is currently not considered separately from dynamic friction. This may be fixed in the future.
- Restitution might not be quite as perfect in some instances (this is a tradeoff for speculative collision to avoid tunneling).
- 2D applications may need to configure the `PhysicsLengthUnit` to get the best stability and behavior.

The `PhysicsLengthUnit` can be thought of a pixels-per-meter scaling factor for the engine's internal length-based tolerances and thresholds, such as the maximum speed at which overlap is resolved, or the speed threshold for allowing bodies to sleep. It does *not* scale actual physics objects or their velocities.

To configure the `PhysicsLengthUnit`, you can insert it as a resource, or simply set it while adding `PhysicsPlugins`:

```rust
fn main() {
    App::new()
        .add_plugins((
            DefaultPlugins,
            // A 2D game with 20 pixels per meter
            PhysicsPlugins::default().with_length_unit(20.0),
        ))
        .run();
}
```

### Custom Constraints

Custom constraints using XPBD are currently still possible. However, the traits and systems are now located in the `dynamics::solver::xpbd` module, and users should run `solve_constraints` in `SubstepSolverSet::SolveUserConstraints` instead of `SubstepSet::SolveUserConstraints`.

### Scheduling Changes

Several scheduling internals have been changed. For example:

- The narrow phase and `PostProcessCollisions` schedule are now run in `PhysicsStepSet::NarrowPhase` instead of `SubstepSet::NarrowPhase`.
- Integration is now run in `IntegrationSet::Velocity` and `IntegrationSet::Position` instead of `SubstepSet::Integrate`.
- `SubstepSet` has been removed.
	- The solver runs in `PhysicsStepSet::Solver`.
	- The solver's system sets are in `SolverSet`.
	- Substepping is performed in `SolverSet::Substep`.
	- The substepping loop's system sets are in `SubstepSolverSet`.

Systems running in `PostProcessCollisions` may need to be modified to account for it being moved outside of the substepping loop.
# Objective

The joint code has a lot of ugly parts:

- 2D joints are implemented as just 3D joints with Z as the rotation axis instead of being "true" 2D.
- `SphericalJoint` exists in 2D even though it doesn't really work since it's a 3D joint.
- Lagrange update computation often unnecessarily takes unit gradients. The gradients aren't needed if they have unit length, and in our case they do.
- Some variable and method names are very vague, like `delta_q` or `p` instead of `rotation_difference` and `impulse`.
- The 3D `AngleLimit::compute_correction` method has no comments or explanations for the angle magic it does.

## Solution

Fix the issues :)

I also did some other small cleanup and fixed some intra-doc links.

---

## Migration Guide

- `SphericalJoint` no longer exists in 2D. Use `RevoluteJoint` instead.
- `AngleLimit` properties `alpha` and `beta` are now named `min` and `max`.
- `apply_positional_correction` has been renamed to `apply_positional_lagrange_update`. There is also an `apply_positional_impulse` method.
- `apply_angular_correction` has been renamed to `apply_angular_lagrange_update`. There is also an `apply_angular_impulse` method.
- `compute_lagrange_update` no longer takes a slice over gradients. For that, use `compute_lagrange_update_with_gradients`.
- `Joint::align_orientation` has been moved to `AngularConstraint`.
# Objective

#385 added speculative collision, a form of Continuous Collision Detection (CCD) with the goal of preventing tunneling. However, it isn't perfect; speculative collision can sometimes cause ghost collisions, and it can miss collisions against objects spinning at very high speeds.

Another form of CCD is swept CCD, which sweeps colliders from their previous positions to the current ones, and moves the bodies to the time of impact if a hit was found. This can be more reliable than speculative collision, and can act as a sort of safety net when you want to ensure that an object has no tunneling, at the cost of being more expensive and causing "time loss" where bodies appear to stop momentarily as they are brought back in time.

Both forms of CCD are valuable and should exist. They can also be used together to complement each other!

## Solution

Add a `CcdPlugin` that performs sweep-based CCD for rigid bodies that have the `SweptCcd` component.

```rust
commands.spawn((
    RigidBody::Dynamic,
    Collider::circle(0.5),
    // Enable swept CCD for this rigid body.
    SweptCcd::default(),
));
```

Two sweep modes are supported:

- If `SweptCcd::mode` is `SweepMode::Linear`, only translational motion is considered.
- If `SweptCcd::mode` is `SweepMode::NonLinear`, both translational and rotational motion are considered. This is more expensive.

By default, the mode is `SweepMode::NonLinear`, but it can be specified using associated constants `SweptCcd::Linear` or `SweptCcd::NonLinear`, or by using the `SweptCcd::new_with_mode` constructor.

It may not be desirable to have CCD enabled for all collisions. To enable it based on the relative velocities of the bodies involved, velocity thresholds can be set:

```rust
SweptCcd::NonLinear.with_velocity_threshold(linear, angular)
```

Additionally, swept CCD can be disabled for collisions against dynamic bodies:

```rust
SweptCcd::NonLinear.include_dynamic(false)
```

Below you can see the new `ccd` example and the different forms of CCD in action!


https://github.com/Jondolf/bevy_xpbd/assets/57632562/2a27d92b-85aa-404e-b258-dcf4f914b12e

As you can see, all the different modes and combinations behave differently, and have their own unique characteristics and trade-offs. In this spinning example, sweep-based CCD clearly has time loss, especially with speculative collision disabled. Non-linear swept CCD is also the most reliable however, as it doesn't let any of the projectiles tunnel through. Linear swept CCD on the other hand struggles a lot in this case since it doesn't take rotational motion into account.

Of course, this is a very extreme and relatively niche example. For most objects in most games, speculative collision should be enough, and swept CCD can be used as a safety net when it isn't.

### Implementation

The implementation works as follows:

- Store broad phase intersections for entities with `SweptCcd` in an `AabbIntersections` component.
- In `solve_swept_ccd`, iterate through the AABB intersections for each entity with `SweptCcd`, and perform shape casts to find the minimum time of impact.
  - If `SweptCcd::mode` is `SweepMode::Linear`, only translational motion is considered.
  - If `SweptCcd::mode` is `SweepMode::NonLinear`, both translational and rotational motion are considered. This is more expensive.
- Integrate the positions of the bodies for the duration of the minimum time of impact to move them into a touching state.
- Normal collision detection and collision response will handle the collision during the next frame.

A number of physics engines were used as inspiration for the implementation and terminology, primarily Box2D V3, Bepu, and Jolt.

Unlike Rapier, I did not implement substepping for the time of impact solver, because it is more expensive and complex, and likely much more difficult to parallelize in the future. I believe Box2D V3 is opting for a similar approach for similar reasons.
# Objective

The `new` constructors for Bevy's `Cylinder`, `Capsule`, and `Cone` shapes take a radius first, and a height second.

```rust
Capsule::new(radius, height)
```

However, our collider constructors use the opposite order:

```rust
Collider::capsule(height, radius)
```

The reason for this is that I originally followed Parry's argument ordering, and Bevy's primitive shapes were added afterwards with a different ordering.

This is a very unfortunate inconsistency and can easily lead to confusion. Even though changing this will lead to very clear breakage for a large number of applications, I believe it is important that we align ourselves with Bevy here.

## Solution

Make the argument ordering for all collider constructors match Bevy.

---

## Migration Guide

To match Bevy's `Cylinder`, `Capsule`, and `Cone`, the order of arguments has changed for some `Collider` constructors.

- Use `Collider::cylinder(radius, height)` instead of `Collider::cylinder(height, radius)`.
- Use `Collider::capsule(radius, height)` instead of `Collider::capsule(height, radius)`.
- Use `Collider::capsule_endpoints(radius, a, b)` instead of `Collider::capsule_endpoints(a, b, radius)`.
- Use `Collider::cone(radius, height)` instead of `Collider::cone(height, radius)`.
# Objective

Collisions for thin objects such as triangle meshes can sometimes have stability and performance issues, especially when dynamically colliding against other thin objects.

- Infinitely thin objects are more prone to numerical issues and tunneling. Two trimeshes colliding against each other can easily get stuck in an intersecting state or have other collision issues.
- Collision algorithms for intersecting objects are typically more expensive than for the non-intersecting state. Trimesh collisions can be very expensive if the trimesh has dense geometry.

To allow users to mitigate these issues when necessary, engines such as Rapier and Bullet provide a *collision margin* or *contact skin* that forces the solver to maintain an artificial separation distance between objects. It can be thought of as a kind of shell that adds thickness to colliders, reducing the issues mentioned above.

## Solution

Add a `CollisionMargin` component. It can be used to add artifical thickness to any collider for collisions.

```rust
commands.spawn((
    RigidBody::Dynamic,
    Collider::trimesh_from_mesh(&mesh),
    CollisionMargin(0.05),
));
```

Without a collision margin:

https://github.com/Jondolf/bevy_xpbd/assets/57632562/0364168b-81e9-4887-a2fa-10a23b87481e

With a collision margin:

https://github.com/Jondolf/bevy_xpbd/assets/57632562/b41a3cbc-0709-4c3f-9f20-1b73d2d48e76

---------

Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
# Objective

Updated version of #351.

A lot of types are missing `ReflectSerialize` and `ReflectDeserialize` implementations with the `serialize` feature enabled, and several types are also not registered in the `TypeRegistry`.

## Solution

Add `#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize)]` for types that were missing it, and register more types in the `PhysicsTypeRegistrationPlugin`. I also fixed and added some other derives, including removing `Component` from `CoefficientCombine`.

---

## Migration Guide

`CoefficientCombine` is no longer a component. It was never supposed to be one, and did nothing on an entity anyways.

---------

Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
@Jondolf Jondolf merged commit 7ec3d1d into main Jul 5, 2024
4 checks passed
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.

Rebrand Bevy XPBD and Switch Solvers
1 participant