avian

ECS-driven 2D and 3D physics engine for the Bevy game engine.

APACHE-2.0 License

Downloads
22.7K
Stars
1.4K
Committers
50

Bot releases are hidden (Show)

avian - v0.1.2 Latest Release

Published by Jondolf 2 months ago

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

avian - v0.1.1

Published by Jondolf 2 months ago

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

avian - Avian 0.1

Published by Jondolf 3 months ago

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

Rotation Component #370

The Rotation component has been updated to match the API of Bevy's new Rot2 type more closely.

The primary breaking changes are that rotate and mul have been deprecated in favor of Mul implementations, and the 2D from_radians and from_degrees have been renamed to just radians and degrees.

// Before
let rotation = Rotation::from_degrees(45.0);
assert_eq!(rotation.mul(rotation).rotate(Vec2::X), Vec2::Y);

// After
let rotation = Rotation::degrees(45.0);
assert_eq!(rotation * rotation * Vec2::X, Vec2::Y);

Add and Sub implementations have also been removed, as adding or subtracting quaternions in 3D is not quite equivalent to performing rotations, which can be a footgun, and having the 2D version function differently would also be inconsistent.


What's Changed

Note: These are changes made between Bevy XPBD 0.4 and Avian 0.1.

New Contributors

Full Changelog: https://github.com/Jondolf/bevy_xpbd/compare/xpbd-v0.4.0...v0.1.0

avian - Bevy XPBD v0.5.0

Published by Jondolf 4 months ago

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

New Contributors

Full Changelog: https://github.com/Jondolf/bevy_xpbd/compare/v0.4.0...v0.5.0

avian - v0.4.0

Published by Jondolf 8 months ago

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

New Contributors

Full Changelog: https://github.com/Jondolf/bevy_xpbd/compare/v0.3.0...v0.4.0

avian - v0.3.0

Published by Jondolf 12 months ago

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_mesh → trimesh_from_mesh
  • convex_decomposition_from_bevy_mesh → convex_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

New Contributors

Full Changelog: https://github.com/Jondolf/bevy_xpbd/compare/v0.2.0...v0.3.0

avian - v0.2.0

Published by Jondolf over 1 year ago

Biggest features and changes

  • Added spatial queries: Ray casting, shape casting, point projection, intersection tests
  • Updated to Bevy 0.11
  • Improved scheduling and system sets
    • PhysicsPlugins accepts any schedule for running the PhysicsSchedule
    • Added PhysicsTimestep::FixedOnce
    • Simplified system sets
  • Added LinearDamping and AngularDamping
  • Added GravityScale
  • Improved force and torque API, e.g. persistence property and apply_at_point
  • Added LockedAxes
  • Added basic dynamic and kinematic character controller examples
  • Improved docs
    • Added short section on server usage
    • Added comparison to Rapier in FAQ
    • Improved XPBD explanation a bit
  • A lot of bug fixes

What's Changed

New Contributors

Full Changelog: https://github.com/Jondolf/bevy_xpbd/compare/v0.1.0...v0.2.0

avian - v0.1.0

Published by Jondolf over 1 year ago

Release 0.1.0