Skip to content

Releases: Jondolf/avian

v0.3.1

05 Jun 09:11
Compare
Choose a tag to compare

What's Changed

  • Fix body property of collision events and reflect CollisionEventsEnabled properly by @Jondolf in #752

Full Changelog: v0.3.0...v0.3.1

Avian v0.3.0

09 May 22:33
2d27900
Compare
Choose a tag to compare

Avian Physics 0.3 has been released! 🪶

Avian 0.3 cover image

Highlights

Avian 0.3 is another huge release, with several new features, quality-of-life improvements, and important bug fixes. Highlights include:

  • Opt-in contact reporting: Collision events are now only sent for entities that have the CollisionEventsEnabled component, reducing unwanted overhead and iteration.
  • Observable collision events: Observers finally support collision events, making it easy to define per-entity collision handlers.
  • Collision hooks: Users can "hook into" the collision pipeline, making it possible to efficiently filter and modify contacts.
  • Per-manifold material properties: Friction, restitution, and tangent velocity can be modified for contact manifolds, allowing the simulation of non-uniform materials and conveyor belts.
  • Collider context: Custom colliders that implement AnyCollider have a Context for ECS access.
  • Physics diagnostics: Avian has built-in diagnostics and a debug UI for runtime physics profiling.
  • Reworked contact pair management: Contacts have been massively reworked to reduce allocations and unnecessary work while increasing parallelism.
  • Faster collisions and spatial queries: Collisions and spatial queries have much less overhead.
  • Bevy 0.16 support: Avian has been updated to the latest version of Bevy, and is taking advantage of relationships for attaching colliders to rigid bodies.

Check out the announcement blog post for a more in-depth overview of what has changed and why. A more complete changelog can also be found after the migration guide below.

Migration Guide

Collision Hooks #610

The BroadPhasePlugin, NarrowPhasePlugin, and many NarrowPhase methods now take generics for CollisionHooks. If you have no collision hooks, you can use ().

Physics Picking #632

The RenderLayers of cameras and collider entities no longer affect physics picking. Add the new PhysicsPickingFilter component to cameras to control which CollisionLayers and colliders are included in picking.

Default Layers for ColliderConstructorHierarchy #649

ColliderConstructorHierarchy now defaults to one membership (the first layer) and all filters for the CollisionLayers of generated colliders. This is consistent with how the CollisionLayers component already works normally.

Previously, it was still using the old default of all memberships and all filters.

Improved Contact Types #616 #685

There have been several changes to Avian's contact types to make them more optimized and clear.

Contacts

  • Contacts has been renamed to ContactPair.
  • The total_normal_impulse property has been replaced with a total_normal_impulse helper method.
  • The total_normal_force helper has been deprecated. Instead, just divide the impulse by the substep timestep.
  • The total_tangent_impulse property and total_friction_force helper have been removed for being inaccurate/misleading. The tangent impulse magnitudes of each individual point can still be accessed.

ContactManifold

  • ContactManifold::contacts has been renamed to ContactManifold::points.
  • The local normal1 and normal2 have been replaced with a single world-space normal, pointing from the first shape to the second.

ContactData

  • ContactData has been renamed to ContactPoint, since it specifically represents a point in a contact manifold, not general contact data.
  • point1 and point2 have been renamed to local_point1 and local_point2 for explicitness.
  • normal1 and normal2 have been removed, since the normal is already stored in the ContactManifold.

Add Context to AnyCollider #665

  • AnyCollider implementors now need to specify a Context associated SystemParam. If this is unnecessary, () should be used.
  • When trying to use methods from AnyCollider on an implementation with () context, SimpleCollider should be used instead.
  • Methods on AnyCollider have been suffixed with _with_context.

Bevy 0.16 Support #670

Avian now uses Bevy 0.16.

The AncestorMarkerPlugin no longer requires a schedule or system set.

Change ColliderParent to ColliderOf relationship #671

The ColliderParent component has been renamed to ColliderOf, and it is now a Relationship. The ColliderHierarchyPlugin (included in PhysicsPlugins) must be enabled for colliders to be automatically attached to rigid bodies, but ColliderOf can also be inserted manually otherwise.

The transform management in ColliderHierarchyPlugin has been extracted into a new ColliderTransformPlugin. The ColliderHierarchyPlugin no longer takes a schedule.

Reworked Contact Pair Management #683

Avian's collision detection pipelines and contact pair management have been massively reworked for better performance and robustness.

PostProcessCollisions

The PostProcessCollisions schedule and NarrowPhaseSet::PostProcess system set have been removed, as it is incompatible with new optimizations to narrow phase collision detection. Instead, use CollisionHooks for contact modification.

Contact Reporting

The ContactReportingPlugin and PhysicsStepSet::ReportContacts system set have been removed. Contact reporting is now handled by the NarrowPhasePlugin directly.

The Collision event no longer exists. Instead, use Collisions directly, or get colliding entities using the CollidingEntities component.

The CollisionStarted and CollisionEnded events are now only sent if either entity in the collision has the CollisionEventsEnabled component. If you'd like to revert to the old behavior of having collision events for all entities, consider making CollisionEventsEnabled a required component for Collider:

app.register_required_components::<Collider, CollisionEventsEnabled>();

Collisions

The Collisions resource is now a SystemParam.

// Old
fn iter_collisions(collisions: Res<Collisions>) {
    todo!()
}

// New
fn iter_collisions(collisions: Collisions) {
    todo!()
}

Internally, Collisions now stores a ContactGraph that stores both touching and non-touching contact pairs. The Collisions system parameter is just a wrapper that provides a simpler API and only returns touching contacts.

The collisions_with_entity method has also been renamed to collisions_with, and all methods that mutatate, add, or remove contact pairs have been removed from Collisions. However, the following mutating methods are available on ContactGraph:

  • get_mut
  • iter_mut
  • iter_touching_mut
  • collisions_with_mut
  • add_pair/add_pair_with_key
  • insert_pair/insert_pair_with_key
  • remove_pair
  • remove_collider_with

For most scenarios, contact modification and removal are intended to be handled with CollisionHooks.

ContactPair (previously Contacts)

The during_current_frame and during_previous_frame properties of ContactPair have been removed in favor of a flags property storing information in a more compact bitflag format. The is_sensor, is_touching, collision_started, and collision_ended helper methods can be used instead.

ContactManifold

Methods such as AnyCollider::contact_manifolds_with_context now take &mut Vec<ContactManifold> instead of returning a new vector every time. This allows manifolds to be persisted more effectively, and reduces unnecessary allocations.

BroadCollisionPairs

The BroadCollisionPairs resource has been removed. Use the ContactGraph resource instead.

AabbIntersections

The AabbIntersections component has been removed. Use ContactGraph::entities_colliding_with instead.

Change CollisionLayers to a Required Component #693

CollisionLayers is now a required component for colliders and is inserted automatically. Collision detection may not work properly without it.

Reorganize Collision Detection Modules and Re-Exports #698

Some collision detection modules and imports have been reorganized.

The following modules have been moved:

  • layers from collision to collision::collider
  • contact_query from collision to collision::collider::parry
  • feature_id from collision to collision::contact_types

Previously, a lot of collision detection types were also re-exported directly from the collision module. Now, there is instead a prelude for the collision module.

Contact Constraint Generation System Ordering #699

NarrowPhaseSet::GenerateConstraints has been removed. Contact constraints are now generated as part of NarrowPhaseSet::Update.

Rename Entity Properties #718 #719

  • ContactPair: The entity1 and entity2 properties are now collider1 and collider2, and body_entity1 and body_entity2 are now body1 and body2.
  • ContactConstraint: The entity1 and entity2 properties are now body1 and body2, and collider_entity1 and collider_entity2 are now collider1 and collider2.
  • ColliderQuery: The rigid_body property has been renamed to of (for ColliderOf) and there is a new body helper to get the contained entity directly.

What's Changed

  • Collision Hooks @Jondolf in #610
  • Fix collisions not being cleared for immediately despawned entities by @Jondolf in #642
  • Introduce PhysicsPickingFilter by @morgenthum in #632
  • Remove unnecessary cfg_attr from from_shape mass helpers by @jondol...
Read more

v0.2.1

26 Jan 14:22
Compare
Choose a tag to compare

What's Changed

New Contributors

Full Changelog: v0.2.0...v0.2.1

Avian v0.2.0

21 Dec 00:22
5b80901
Compare
Choose a tag to compare

Avian Physics 0.2 has been released! 🪶

Avian 0.2 cover image

Highlights

Avian 0.2 is another massive release, with several new features, quality-of-life improvements, and important bug fixes. Highlights include:

  • Reworked scheduling: Avian now runs in Bevy's FixedPostUpdate instead of having its own fixed timestep in PostUpdate, simplifying scheduling and fixing several common footguns.
  • Transform interpolation: Movement at fixed timesteps can be visually smoothed with built-in transform interpolation or extrapolation.
  • Mass property rework: Mass properties have been overhauled from the ground up to be much more intuitive, flexible, and configurable.
  • Physics picking: Colliders have a picking backend for bevy_picking.
  • Disabling physics entities: Rigid bodies, colliders, and joints can be temporarily disabled with marker components.
  • Better defaults: Collision layers, friction, and restitution now have more sensible and configurable defaults.
  • Improved 3D friction: Friction behavior in 3D is much more stable and realistic than before.
  • Limit maximum speeds: The maximum speed of rigid bodies can be easily clamped for stability and gameplay purposes.
  • Bevy 0.15 support: Avian supports the latest version of Bevy.

Check out the announcement blog post for a more in-depth overview of what has changed and why. A more complete changelog can also be found after the migration guide below.

Migration Guide

Take SpatialQueryFilter by reference in spatial queries #402

Spatial queries performed through SpatialQuery now take SpatialQueryFilter by reference.

Use hooks for component initialization #483

PrepareSet::PreInit has been renamed to PrepareSet::First, and PrepareSet::InitRigidBodies, PrepareSet::InitColliders, and PrepareSet::InitMassProperties have been removed. Most missing components are now initialized by component lifecycle hooks.

CcdPlugin and SpatialQueryPipeline no longer store a schedule and are now unit structs. Instead of SpatialQueryPlugin::new(my_schedule) or SpatialQueryPlugin::default(), just use SpatialQueryPlugin.

Use FixedPostUpdate by default and simplify scheduling #457

Previously, physics was run in PostUpdate with a custom fixed timestep by default. The primary purpose of the fixed timestep is to make behavior consistent and frame rate independent.

This custom scheduling logic has been removed, and physics now runs in Bevy's FixedPostUpdate by default. This further unifies physics with Bevy's own APIs and simplifies scheduling. However, it also means that physics now runs before Update, unlike before.

For most users, no changes should be necessary, and systems that were running in Update can remain there. If you want to run systems at the same fixed timestep as physics, consider using FixedUpdate.

The Time<Physics> clock now automatically follows the clock used by the schedule that physics is run in. In FixedPostUpdate and other schedules with a fixed timestep, Time<Fixed> is used, but if physics is instead configured to run in a schedule with a variable timestep, like PostUpdate, it will use Time<Virtual>.

Previously, the physics timestep could be configured like this:

app.insert_resource(Time::new_with(Physics::fixed_hz(60.0)));

Now, if you are running physics in FixedPostUpdate, you should simply configure Time<Fixed> directly:

app.insert_resource(Time::<Fixed>::from_hz(60.0)));

The following types and methods have also been removed as a part of this rework:

  • TimestepMode
  • Physics::from_timestep
  • Physics::fixed_hz
  • Physics::fixed_once_hz
  • Physics::variable
  • Time::<Physics>::from_timestep
  • Time::<Physics>::timestep_mode
  • Time::<Physics>::timestep_mode_mut
  • Time::<Physics>::set_timestep_mode

Previously, camera following logic had to be scheduled relative to both physics and transform propagation:

// Run after physics, before transform propagation.
app.add_systems(
    PostUpdate,
    camera_follow_player
        .after(PhysicsSet::Sync)
        .before(TransformSystem::TransformPropagate),
);

Since physics is now run in FixedPostUpdate, which is before Update, it is enough to order the system against just transform propagation:

// Note: camera following could technically be in `Update` too now.
app.add_systems(
    PostUpdate,
    camera_follow_player.before(TransformSystem::TransformPropagate),
);

Use a single layer as the default membership instead of all #476 #494

Previously, CollisionLayers defaulted to "all memberships, all filters", meaning that everything belonged to every layer and could interact with every layer. This turned out to be very limiting in practice, as it made it impossible to target things like ray casts to specific layers, unless the memberships of all colliders were set explicitly.

Now, colliders only belong to the first layer by default. This means that the first bit 0b0001 in the layer mask is reserved for the default layer.

This also applies to enum-based layers using the PhysicsLayer derive macro. To make the default layer explicit, physics layer enums must now implement Default, and specify which variant represents the default layer 0b0001.

#[derive(PhysicsLayer, Default)]
enum GameLayer {
    #[default]
    Default, // The name doesn't matter, but Default is used here for clarity
    Player,
    Enemy,
    Ground,
}

Rework mass properties #500 #532 #574

Inverse Mass Components

  • InverseMass and InverseInertia have been removed, and Inertia has been renamed to AngularInertia.
  • RigidBodyQueryItem methods effective_inv_mass and effective_world_inv_inertia have been renamed to effective_inverse_mass and effective_global_inverse_inertia.

MassPropertyPlugin

The MassPropertyPlugin is now needed to update mass properties automatically based on attached colliders. Most apps won't need to add it manually, as it is included in the PhysicsPlugins plugin group by default.

Behavior Changes

  • Mass, AngularInertia, and CenterOfMass are now optional, and can be used to override the mass properties of an entity if present, ignoring the entity's collider. Mass properties that are not set are still computed from the entity's Collider and ColliderDensity.
  • Mass properties of child entities still contribute to the total mass properties of rigid bodies by default, but the total values are stored in ComputedMass, ComputedAngularInertia, and ComputedCenterOfMass instead of Mass, AngularInertia, and CenterOfMass. The latter components are now never modified by Avian directly.
  • To prevent colliders or descendants from contributing to the total mass properties, add the NoAutoMass, NoAutoAngularInertia, and NoAutoCenterOfMass marker components to the rigid body, giving you full manual control.
  • Previously, changing Mass at runtime did not affect angular inertia. Now, it is scaled accordingly, unless NoAutoAngularInertia is present.
  • Previously, specifying the CenterOfMass at spawn did nothing unless an initial Mass was specified, even if the entity had a collider that would give it mass. This has been fixed.
  • Previously, Mass, AngularInertia, and CenterOfMass did nothing on child colliders. Now, they effectively override ColliderMassProperties when computing the total mass properties for the rigid body.
  • Previously, zero mass and angular inertia were treated as invalid. It emitted warnings, which was especially problematic and spammy for runtime collider constructors. Now, they are treated as acceptable values, and interpreted as infinite mass, like in most other engines.

API Changes

  • Mass, AngularInertia, CenterOfMass, ColliderDensity, and ColliderMassProperties now always use f32 types, even with the f64 feature. Total mass properties stored in ComputedMass, ComputedAngularInertia, and ComputedCenterOfMass still support f64.
  • In 3D, AngularInertia now stores a principal angular inertia (Vec3) and the orientation of the local inertial frame (Quat) instead of an inertia tensor (Mat3). However, several different constructors are provided, including from_tensor.
  • MassPropertiesBundle::new_computed and ColliderMassProperties::from_collider have been renamed to from_shape.
  • ColliderMassProperties now stores a MassProperties2d/MassProperties3d instead of separate properties.
  • Types implementing AnyCollider must now also implement the ComputeMassProperties2d/ComputeMassProperties3d trait instead of the mass_properties method.

Collider Constructors #540

Collider::regular_polygon and ColliderConstructor::RegularPolygon now use a u32 instead of usize for sides.

Use required components for component initialization #541

The CollidingEntities component is no longer added automatically. To read entities that are colliding with a given entity, you must now add the CollidingEntities component for it manually.

To revert to the old behavior, you can also make CollidingEntities a required component for colliders:

app.register_required_components::<Collider, CollidingEntities>();

Improvements to friction and restitution #551

Friction and Restitution are no longer inserted automatically for rigid bodies. Instead, there are now DefaultFriction and DefaultRestitution resources, whic...

Read more

v0.1.2

10 Aug 18:55
Compare
Choose a tag to compare

A full diff of what has been fixed can be seen here: v0.1.1...v0.1.2

v0.1.1

07 Aug 18:10
Compare
Choose a tag to compare

A full diff of what has been fixed can be seen here: v0.1.0...v0.1.1

Avian v0.1.0

06 Jul 00:07
Compare
Choose a tag to compare

Avian Physics 0.1 has been released! 🪶

Avian Physics logo

Avian is an ECS-driven physics engine for the Bevy game engine. It is the next evolution of Bevy XPBD, with a completely rewritten contact solver, improved performance, a reworked structure, and numerous other improvements and additions over its predecessor.

See #346 for background on the rebrand.

Highlights

Avian 0.1 has a ton of improvements, additions, and fixes over Bevy XPBD 0.4. Some highlights:

  • A solver rewrite: Avian uses an impulse-based TGS Soft solver instead of XPBD for contacts.
  • A reworked narrow phase: Collision detection is much more performant and reliable.
  • Continuous Collision Detection (CCD): Speculative collision and sweep-based CCD are implemented to prevent tunneling.
  • Optional collision margins: Extra thickness can be added for thin colliders such as trimeshes to improve stability and performance.
  • Improved performance: Overhead for large scenes is significantly smaller, and collision-heavy scenes can have over a 4-6x performance improvement in comparison to Bevy XPBD.
  • Improved runtime collider constructors: It is easier to define colliders and collider hierarchies statically to enable more powerful scene workflows.
  • Structural improvements and polish: The module structure has been heavily reworked, and tons of inconsistencies and bugs have been resolved.
  • Bevy 0.14 support: Avian supports the latest version of Bevy, and internally, it already takes advantage of new features such as observers and component lifecycle hooks.

Check out the announcement blog post for a more in-depth overview of what has changed and why. A more complete changelog can also be found after the migration guide below.

Migration Guide

Note: This guide is for migration from Bevy XPBD 0.4 to Avian 0.1. The entries for migration to Bevy XPBD 0.5 (an easier migration path) still apply and are also listed here.

New Contact Solver #385

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 resource.
  • 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 common user-facing inputs or outputs like colliders or velocities.

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

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

Collider Constructor Argument Order #394

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).

This is a very heavily breaking change, but I believe it is important that we align ourselves with Bevy here, and it's better to do it sooner rather than later.

AsyncCollider and AsyncSceneCollider #378

AsyncCollider, AsyncSceneCollider, and ComputedCollider have been replaced by more powerful ColliderConstructor and ColliderConstructorHierarchy types. They work similarly, but also support primitive shapes and arbitrary hierarchies, not just colliders computed for meshes and scenes.

Additionally, some naming changes have been made to improve consistency, such as renaming TriMesh to Trimesh to be consistent with Collider::trimesh.

  • Remove feature async-collider. If you need to use computed shapes, use the feature collider-from-mesh. If you depend on ColliderConstructorHierarchy waiting for a scene to load, use the feature bevy_scene
  • Remove AsyncCollider and use ColliderConstructor directly
  • Rename AsyncSceneCollider to ColliderConstructorHierarchy
    • Rename AsyncSceneCollider::default_shape to ColliderConstructorHierarchy::default_constructor
    • Rename AsyncSceneCollider::meshes_by_name to ColliderConstructorHierarchy::config
    • Rename AsyncSceneCollider::with_shape_for_name to ColliderConstructorHierarchy::with_constructor_for_name
    • Rename AsyncSceneCollider::without_shape_for_name to ColliderConstructorHierarchy::without_constructor_for_name
  • Rename AsyncSceneColliderData to ColliderConstructorHierarchyConfig
    • Rename AsyncSceneColliderData::shape to ColliderConstructorHierarchyConfig::constructor
  • Rename ComputedCollider to ColliderConstructor.
    • Rename ComputedCollider::TriMesh to ColliderConstructor::TrimeshFromMesh
    • Rename ComputedCollider::TriMeshWithFlags to ColliderConstructor::TrimeshFromMeshWithConfig
    • Rename ComputedCollider::ConvexHull to ColliderConstructor::ConvexHullFromMesh
    • Rename ComputedCollider::ConvexDecomposition to ColliderConstructor::ConvexDecompositionFromMeshWithConfig
  • Rename VHACDParameters to VhacdParameters
  • Rename Collider::halfspace to Collider::half_space

Reworked Module Structure #370

  • 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.

Sensor Mass Properties #381

Colliders with the Sensor component no longer contribute to the mass properties of rigid bodies. You can add mass for them by adding another collider that is not a sensor, or by manually adding mass properties with the MassPropertiesBundle or its components.

Additionally, the mass properties of Sensor colliders are no longer updated automatically, unless the Sensor component is removed.

Joints and Custom Constraints #390 and #385

  • 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.
  • XPBD traits and systems are now located in the dynamics::solver::xpbd module.
  • User constraints should run solve_constraints in SubstepSolverSet::SolveUserConstraints instead of SubstepSet::SolveUserConstraints.

Scheduling Changes #385 and #380

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.

Some PrepareSet system sets have also changed order.

Before:

  1. PreInit
  2. PropagateTransforms
  3. InitRigidBodies
  4. InitMassProperties
  5. InitColliders
  6. InitTransforms
  7. Finalize

After:

  1. PreInit
  2. InitRigidBodies
  3. InitColliders
  4. PropagateTransforms
  5. InitMassProperties
  6. InitTransforms
  7. Finalize

ColliderHierarchyPlugin #377

Hierarchy and transform logic for colliders has been extracted from the ColliderBackendPlugin into a new `ColliderHierarchy...

Read more

Bevy XPBD v0.5.0

04 Jul 17:26
Compare
Choose a tag to compare

Bevy XPBD 0.5 is the final version of Bevy XPBD, and will be deprecated in favor of Avian, which is coming very, very soon. This release is primarily a Bevy 0.14 upgrade with very few breaking changes to ease migration. Avian 0.1 will have the majority of the changes.

The main changes and improvements in Bevy XPBD 0.5 are:

  • Bevy 0.14 support.
  • Transform propagation has significantly less overhead, as it is only performed for physics entities.
  • Sensor colliders no longer contribute to mass properties.
  • 2D heightfields take a Vec2 instead of a scalar value for scale.
  • Some bug fixes, like rotation normalization in constraints to prevent explosive behavior.

Migration Guide

Sensor Mass Properties (#381)

Colliders with the Sensor component no longer contribute to the mass properties of rigid bodies. You can add mass for them by adding another collider that is not a sensor, or by manually adding mass properties with the MassPropertiesBundle or its components.

Additionally, the mass properties of Sensor colliders are no longer updated automatically, unless the Sensor component is removed.

PrepareSet System Set Order (#380)

Some PrepareSet system sets have changed order.

Before:

  1. PreInit
  2. PropagateTransforms
  3. InitRigidBodies
  4. InitMassProperties
  5. InitColliders
  6. InitTransforms
  7. Finalize

After:

  1. PreInit
  2. InitRigidBodies
  3. InitColliders
  4. PropagateTransforms
  5. InitMassProperties
  6. InitTransforms
  7. Finalize

ColliderHierarchyPlugin (#377)

Hierarchy and transform logic for colliders has been extracted from the ColliderBackendPlugin into a new ColliderHierarchyPlugin, which by default is included in the PhysicsPlugins plugin group.

If you are adding plugins manually, make sure you have both if you want that functionality.

What's Changed

  • Fix time of impact description in ShapeHits by @Jondolf in #340
  • Fix 2D heightfield scale and docs by @Jondolf in #343
  • Fix 3D ShapeCaster global_rotation by @ramon-oliveira in #344
  • Normalize rotations after solving constraints in solver by @Jondolf in #345
  • Add feature to examples_common to enable PhysicsDebugPlugin by @jpedrick in #339
  • Use compile_error! macro instead of panicking in PhysicsLayer derive macro by @doonv in #347
  • Fix some doc tests by @yrns in #354
  • various fixes in the prepare/init_transforms system by @exoexo-dev in #360
  • Implement RegularPolygon colliders with a custom shape by @Jondolf in #367
  • Update bevy-0.14 branch to crates.io release of nalgebra by @gmorenz in #372
  • Speed up ColliderTransform propagation and extract collider hierarchy logic into ColliderHierarchyPlugin by @Jondolf in #377
  • Refactor and speed up transform propagation and hierarchies further by @Jondolf in #380
  • Make sensors not contribute to mass properties by @Jondolf in #381
  • Fix GlobalTransform updates for entities with non-physics children by @Jondolf in #392

New Contributors

Full Changelog: v0.4.0...v0.5.0

Bevy XPBD v0.4.0

20 Feb 18:47
Compare
Choose a tag to compare

Bevy XPBD 0.4 features several new features, bug fixes, and quality of life improvements. Here are some highlights:

  • Generic colliders: Bevy XPBD no longer relies on just Collider for collision detection. You can implement custom collision backends!
  • Parry and Nalgebra are optional: The Parry and Nalgebra dependencies are now behind feature flags (enabled by default). If you don't need collision detection or have a custom collision backend, you can disable them!
  • Access contact impulses: It is often useful to know how strong collisions are. This information is now available in Collision events and the Collisions resource.
  • Debug render contacts: Contact normals and impulses can now be debug rendered.
  • Layer rework: Collision layers have been reworked to be more versatile and explicit with less footguns.
  • Bevy 0.13 support: Bevy XPBD has been updated to the latest version of Bevy.
  • Colliders from primitives: Colliders can be created from the new geometric primitives introduced in Bevy 0.13.
  • PhysicsGizmos gizmo config group: Debug rendering has its own gizmo configuration instead of using the global configuration.

Check out the announcement blog post for a more in-depth overview of what's changed and why. A more complete changelog can also be found after the migration guide below.

Migration Guide

Default Features (#327)

The default Collider now requires either the parry-f32 or parry-f64 feature depending on the precision you are using for Bevy XPBD. However, if you don't need colliders or have a custom collision backend, you can leave the feature disabled.

Layer Rework (#313)

Collision layers have been reworked, see #313.

  • Groups are now called memberships and masks are called filters. This also matches Rapier's naming.
  • Memberships and filters use a type called LayerMask, which is a bitmask for layers and a newtype for u32.
  • All methods like add_group, remove_mask, and so on have been removed. Instead, modify the properties directly.
let layers1 = CollisionLayers::new(0b00010, 0b0111);
let layers2 = CollisionLayers::new(GameLayer::Player, [GameLayer::Enemy, GameLayer::Ground]);
let layers3 = CollisionLayers::new(LayerMask(0b0001), LayerMask::ALL);

Modifying layers is now done by modifying the memberships or filters directly:

layers.memberships.remove(GameLayer::Environment);
layers.filters.add([GameLayer::Environment, GameLayer::Tree]);

// Bitwise ops also work since we're accessing the bitmasks/layermasks directly.
layers.memberships |= GameLayer::Player; // You could also use a bitmask like 0b0010.

Debug rendering

The PhysicsDebugConfig resource and PhysicsDebugRenderer system parameter have been removed in favor of the new PhysicsGizmos gizmo configuration group.

Before:

fn main() {
    App::new()
        .add_plugins((
            DefaultPlugins,
            PhysicsPlugins::default(),
            PhysicsDebugPlugin::default(),
        ))
        // Configure physics debug rendering
        .insert_resource(PhysicsDebugConfig {
            aabb_color: Some(Color::WHITE),
            ..default()
        })
        .run();
}

After:

fn main() {
    App::new()
        .add_plugins((
            DefaultPlugins,
            PhysicsPlugins::default(),
            PhysicsDebugPlugin::default(),
        ))
        // Configure physics debug rendering
        .insert_gizmo_group(
            PhysicsGizmos {
                aabb_color: Some(Color::WHITE),
                ..default()
            },
            GizmoConfig::default(),
        )
        .run();
}

This also allows you to configure e.g. line width for just physics gizmos by configuring their GizmoConfig.

Renamed Collider constructors (#326)

  • Replace Collider::ball with Collider::circle in 2D and Collider::sphere in 3D
  • Replace Collider::cuboid with Collider::rectangle in 2D

Ray and shape casting (#329)

For spatial queries, replace Vec2/Vec3 directions with Direction2d/Direction3d.

// Before
let caster = RayCaster::new(Vec3::ZERO, Vec3::X);

// After
let caster = RayCaster::new(Vec3::ZERO, Direction3d::X);

This applies to RayCaster, ShapeCaster, SpatialQuery methods like cast_ray, and many other methods that use directions.

What's Changed

  • docs: Fix incorrect docs for mass component auto-initialization by @johanhelsing in #234
  • Don't overwrite schedules when adding plugin by @johanhelsing in #236
  • Take child collider rotation into account for contact normals by @Jondolf in #238
  • Fix mesh visibility not being reset when physics debug is disabled by @Jondolf in #242
  • Filter collisions between children of the same rigidbody in broad phase by @mbrea-c in #241
  • Added variant TriMeshWithFlags to ComputedCollider, fix #248 by @Adamkob12 in #251
  • Fix rotations when center of mass is offset by @mbrea-c in #250
  • Use any_orthogonal_vector to get orthogonal vector by @ollef in #255
  • Fix tests and doc examples, make cargo test compile by @Jondolf in #267
  • fix: make clear_forces_and_impulses public by @ActuallyHappening in #257
  • Scale debug rendering of center of mass dot by axis lengths by @Jondolf in #268
  • docs: Added Character Controller recommendation for Bevy Tnua what supports Bevy XPBD by @dror-g in #270
  • Fix Rotation change detection triggering every frame by @Jondolf in #272
  • Don't overwrite Time<Physics> when PhysicsPlugins are added by @johanhelsing in #276
  • Implement MapEntities for AabbIntervals by @johanhelsing in #275
  • Implement MapEntities for collider components by @johanhelsing in #277
  • Apply scale in Collider::set_shape by @Jondolf in #278
  • Fix dead custom constraints link in docs by @PerryPeak in #280
  • Ignore static-static collisions in broad phase by @Jondolf in #283
  • Fix rotation change detection in integrator by @Jondolf in #284
  • Fix static body handling in update_aabb_intervals by @Jondolf in #285
  • Fix DistanceJoint distance limits by @Jondolf in #286
  • Preserve collisions between inactive entities, add sensor example by @TeamDman in #266
  • docs: use the read function for iterating over events by @tremorris1999 in #290
  • docs: corrects other outdated calls to .iter by @tremorris1999 in #291
  • Fix Time inconsistency after substepping loop by @Jondolf in #294
  • Make PreparePlugin configurable by @Rigidity in #292
  • Adding Collider::round_cuboid by @kav in #300
  • Add section about camera following jitter to FAQ by @Jondolf in #305
  • Add intersection and point queries to Collider by @Jondolf in #307
  • Debug render contact normals by @Jondolf in #308
  • Implement cast_ray_predicate to allow filtering the colliders with a function by @Affinator in #297
  • Fix colliders without RigidBody not working by @Jondolf in #323
  • fix raycast does not follow entity transform without rigidbody by @zwazel in #310
  • Store impulses in contacts and refactor contact data by @Jondolf in #324
  • Add ColliderBackendPlugin and support generic colliders by @Jondolf in #311
  • Rework layers by @Jondolf in #313
  • Make Collider optional, allowing usage without Parry or Nalgebra by @Jondolf in #327
  • Fix doc examples by @Jondolf in #330
  • Update to Bevy 0.13 by @Jondolf in #315

New Contributors

Read more

Bevy XPBD v0.3.0

04 Nov 22:16
Compare
Choose a tag to compare

0.3 is a huge release with tons of new features, bug fixes, and quality of life improvements, especially for collision detection. Here are some highlights:

  • Modular narrow phase: Narrow phase collision detection has been refactored into modular plugins instead of being tightly coupled with the solver
  • Improved contact stability: Collisions are significantly more stable, and dynamic friction has been fixed to handle different masses correctly
  • Collider scale: Colliders can be scaled using Transform
  • Child colliders: Colliders can be freely nested using entity hierarchies
  • Async colliders: Colliders can be automatically generated from meshes and glTF scenes
  • Accessing, modifying and filtering collision: The new Collisions resource can be used for accessing and modifying contacts in custom systems
  • Transform for positions: Transform can be used instead of the internal Position and Rotation components
  • Debug rendering: Physics objects and interactions can be rendered for debugging purposes
  • Dominance: Dynamic bodies can be configured to have infinite mass relative to bodies with a lesser dominance
  • Bevy 0.12 support: Bevy XPBD has been updated to Bevy 0.12
  • Time unification: Timing and scheduling resources have been replaced by the unified Time<Physics> and Time<Substeps> resources

Read the more complete changelog after the migration guide for more details.

Migration guide

Here is a (non-exhaustive) migration guide for migrating from 0.2 to 0.3.

Collision iteration

Before:

fn my_system(mut collision_event_reader: EventReader<Collision>) {
    for Collision(contact) in collision_event_reader.iter() {
        println!("Penetration depth: {}", contact.penetration);
    }
}

After:

fn my_system(mut collision_event_reader: EventReader<Collision>) {
    for Collision(contacts) in collision_event_reader.read() {
        for manifold in contacts.manifolds.iter() {
            for contact in manifold.contacts.iter() {
                println!("Penetration depth: {}", contact.penetration);
            }
        }
    }
}

This is more verbose, but it provides multiple contact points instead just one. In the future, this will hopefully be made more ergonomic with helper methods.

A new and more powerful Collisions resource was also added. It can be used to achieve a similar result.

Collider scale (#189)

Before:

let mesh = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
commands.spawn((
    PbrBundle {
        mesh,
        transform: Transform::from_scale(Vec3::new(10.0, 1.0, 10.0)),
        ..default()
    },
    // Collider isn't scaled by transform
    Collider::cuboid(10.0, 1.0, 10.0),
    RigidBody::Static,
));

After:

let mesh = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
commands.spawn((
    PbrBundle {
        mesh,
        transform: Transform::from_scale(Vec3::new(10.0, 1.0, 10.0)),
        ..default()
    },
    // Collider size takes transform scale into account
    Collider::cuboid(1.0, 1.0, 1.0),
    RigidBody::Static,
));

Collider creation from meshes

  • trimesh_from_bevy_meshtrimesh_from_mesh
  • convex_decomposition_from_bevy_meshconvex_decomposition_from_mesh

Unified time (#214)

  • Replace every DeltaTime in PhysicsSchedule and every SubDeltaTime in SubstepSchedule with Time, elsewhere explicitly use Time<Physics> and Time<Substep>
  • When advancing physics manually, instead of setting DeltaTime, advance the Time<Physics> clock using time.advance_by(...)
  • Replace PhysicsTimestep with Time::new_with(Physics::fixed_hz(...)) and so on
  • Replace PhysicsLoop::pause/resume with Time::<Physics>::pause/unpause
  • Replace PhysicsLoop::step with advancing the physics clock using Time::<Physics>::advance_by
  • Replace PhysicsTimescale usage with Time::<Physics>::with/set_relative_speed

What's Changed

  • Debug render colliders by @Jondolf in #73
  • Add more global and entity-level debug render options by @Jondolf in #74
  • Add debug rendering axes and joints and improve configuration API by @Jondolf in #76
  • Move SpatialQuery methods to SpatialQueryPipeline by @LeshaInc in #77
  • Add enabled flag to PhysicsDebugConfig to globally disable debug rendering at runtime by @LeshaInc in #78
  • Add trimesh_with_flags and trimesh_from_bevy_mesh_with_flags by @Jondolf in #79
  • Add PhysicsTimescale resource for slow-motion or fast-forward simulation by @dasisdormax in #80
  • Use world-space center of mass in penetration constraint by @Jondolf in #81
  • Add clear methods for ray and shape hits and clear the hits on disable by @Jondolf in #82
  • Expand AABBs only in the movement direction by @Jondolf in #83
  • Improve simulation stability when object are far from world origin by @LeshaInc in #84
  • Add back global contact positions by @Jondolf in #86
  • Run transform propagation before init_rigid_bodies. Fixes #88 by @LeshaInc in #89
  • Add criterion benchmarks by @LeshaInc in #91
  • Setup PhysicsSchedule and SubstepSchedule to use single-threaded executor by @LeshaInc in #92
  • Use contact manifolds instead of single contacts for collisions by @Jondolf in #90
  • Add ExternalImpulse and ExternalAngularImpulse by @Jondolf in #95
  • Filter operation reodered for a little performance boost by @TrustNoOneElse in #98
  • Store local contact normals and transform them into world-space at each solve by @Jondolf in #97
  • Support Transform for moving and positioning bodies by @Jondolf in #96
  • Fix typo in docs by @Zentropivity in #103
  • Automatically add Position and Rotation for colliders by @Jondolf in #101
  • Separate narrow phase from solver into NarrowPhasePlugin by @Jondolf in #100
  • feature: Add DistanceJoint and 2D and 3D examples. by @shanecelis in #105
  • Debug render rigid body axes at center of mass by @Jondolf in #109
  • Added text that explained how to use the example 'chain_3d' by @Aztro-dev in #107
  • Add "Bounciness" and "Elasticity" aliases for Restitution by @Jondolf in #117
  • Clamp coefficient of restitution between 0 and 1 and improve restitution docs by @Jondolf in #118
  • Add current_position getter for RigidBodyQueryItem by @Jondolf in #120
  • Remove solver iteration loop by @Jondolf in #121
  • Clarify that external forces and impulses are local (edit: not true, fixed by #144) by @Jondolf in #123
  • Register CoefficientCombine by @grace125 in #126
  • Correct time dilation for FixedUpdate schedule. by @starwolfy in #128
  • Fix center of mass and inertia computations and add tests by @Jondolf in #127
  • add Rotation::from_sin_cos constructor by @RJ in #130
  • Avoid allocate on spatial queries. ray_hits_callback, shape_hits_callback, intersections_callback by @bnyu in #133
  • Dynamic friction fix by @felixbjorkeson in #52
  • Fix 2d position_to_transform changing child Transform z-component by @ShaddowSpy in #134
  • Make Rotation & PreviousRotation derive PartialEq by @RJ in #136
  • Fix tests on mac m1 by @RJ in #138
  • Register/Reflect Component of Sensor by @grace125 in #141
  • Fix Transform initialization for children and refactor prepare.rs by @Jondolf in #140
  • Clarify that forces are in world space and improve force docs by @Jondolf in #144
  • Fix math cross-platform determinism by @Jondolf in #145
  • Combine insert calls into bundles to reduce archetype count by @Jondolf in #151
  • Avoid incremental updates to Qbvh by @NiseVoid in #152
  • Fix contact stability for non-convex colliders by @Jondolf in #156
  • Collision post processing by @datael in #155
  • Add Trigger alias for Sensor and improve Sensor docs by @Jondolf in #160
  • Make PreviousGlobalTransform public and derive traits by @Jondolf in #166
  • Add contact queries by ...
Read more