Skip to content

Commit

Permalink
Merge branch 'main' into rework-mass-properties
Browse files Browse the repository at this point in the history
  • Loading branch information
Jondolf committed Oct 12, 2024
2 parents 95abd44 + 4ea5373 commit 7134949
Show file tree
Hide file tree
Showing 14 changed files with 180 additions and 30 deletions.
6 changes: 6 additions & 0 deletions crates/avian2d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ serialize = [
"bevy/serialize",
"parry2d?/serde-serialize",
"parry2d-f64?/serde-serialize",
"bitflags/serde",
]

[lib]
Expand Down Expand Up @@ -71,6 +72,7 @@ bevy_math = { version = "0.14", features = ["approx"] }
approx = "0.5"
criterion = { version = "0.5", features = ["html_reports"] }
insta = "1.0"
bevy_mod_debugdump = "0.11"

[[example]]
name = "dynamic_character_2d"
Expand Down Expand Up @@ -116,6 +118,10 @@ required-features = ["2d", "default-collider"]
name = "revolute_joint_2d"
required-features = ["2d", "default-collider"]

[[example]]
name = "debugdump_2d"
required-features = ["2d"]

[[bench]]
name = "pyramid"
required-features = ["2d", "default-collider"]
Expand Down
18 changes: 18 additions & 0 deletions crates/avian2d/examples/debugdump_2d.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//! Run with:
//! `cargo run --example debugdump_2d > dump.dot && dot -Tsvg dump.dot > dump.svg`

use avian2d::prelude::*;
use bevy::prelude::*;

fn main() {
let mut app = App::new();

app.add_plugins((PhysicsPlugins::default(), PhysicsDebugPlugin::default()));

// Schedules of interest:
// - PhysicsSchedule
// - SubstepSchedule
// - FixedPostUpdate
// - Update
bevy_mod_debugdump::print_schedule_graph(&mut app, PhysicsSchedule);
}
6 changes: 6 additions & 0 deletions crates/avian3d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ serialize = [
"bevy/serialize",
"parry3d?/serde-serialize",
"parry3d-f64?/serde-serialize",
"bitflags/serde",
]

[lib]
Expand Down Expand Up @@ -81,6 +82,7 @@ bevy_math = { version = "0.14", features = ["approx"] }
approx = "0.5"
criterion = { version = "0.5", features = ["html_reports"] }
insta = "1.0"
bevy_mod_debugdump = "0.11"

[[example]]
name = "dynamic_character_3d"
Expand Down Expand Up @@ -134,6 +136,10 @@ required-features = ["3d", "default-collider", "bevy_scene"]
name = "collider_constructors"
required-features = ["3d", "default-collider", "bevy_scene"]

[[example]]
name = "debugdump_3d"
required-features = ["3d"]

[[bench]]
name = "cubes"
required-features = ["3d", "default-collider"]
Expand Down
19 changes: 19 additions & 0 deletions crates/avian3d/examples/debugdump_3d.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//! Run with:
//! `cargo run --example debugdump_3d > dump.dot && dot -Tsvg dump.dot > dump.svg`

use avian3d::debug_render::PhysicsDebugPlugin;
use avian3d::prelude::*;
use bevy::prelude::*;

fn main() {
let mut app = App::new();

app.add_plugins((PhysicsPlugins::default(), PhysicsDebugPlugin::default()));

// Schedules of interest:
// - PhysicsSchedule
// - SubstepSchedule
// - FixedPostUpdate
// - Update
bevy_mod_debugdump::print_schedule_graph(&mut app, PhysicsSchedule);
}
2 changes: 1 addition & 1 deletion crates/examples_common_2d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ bevy = { version = "0.14", default-features = false, features = [
"ktx2",
"zstd",
"bevy_winit",
"x11", # github actions runners don't have libxkbcommon installed, so can't use wayland
"x11", # github actions runners don't have libxkbcommon installed, so can't use wayland
] }
avian2d = { path = "../avian2d", default-features = false }
2 changes: 1 addition & 1 deletion crates/examples_common_3d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ bevy = { version = "0.14", default-features = false, features = [
"png",
"zstd",
"bevy_winit",
"x11", # github actions runners don't have libxkbcommon installed, so can't use wayland
"x11", # github actions runners don't have libxkbcommon installed, so can't use wayland
] }
avian3d = { path = "../avian3d", default-features = false }
72 changes: 59 additions & 13 deletions src/collision/collider/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use std::marker::PhantomData;

use crate::{broad_phase::BroadPhaseSet, prelude::*, prepare::PrepareSet};
use crate::{broad_phase::BroadPhaseSet, prelude::*, prepare::PrepareSet, sync::SyncConfig};
#[cfg(all(feature = "bevy_scene", feature = "default-collider"))]
use bevy::scene::SceneInstance;
use bevy::{
Expand Down Expand Up @@ -95,9 +95,53 @@ impl<C: ScalableCollider> Plugin for ColliderBackendPlugin<C> {

// Initialize missing components for colliders.
hooks.on_add(|mut world, entity, _| {
let entity_ref = world.entity(entity);
let existing_global_transform = world
.entity(entity)
.get::<GlobalTransform>()
.copied()
.unwrap_or_default();
let global_transform = if existing_global_transform != GlobalTransform::IDENTITY {
// This collider was built deferred, probably via `ColliderConstructor`.
existing_global_transform
} else {
// This collider *may* have been `spawn`ed directly on a new entity.
// As such, its global transform is not yet available.
// You may notice that this will fail if the hierarchy's scale was updated in this
// frame. Remember that `GlobalTransform` is not updated in between fixed updates.
// But this is fine, as `update_collider_scale` will be updated in the next fixed update anyway.
// The reason why we care about initializing this scale here is for those users that opted out of
// `update_collider_scale` in order to do their own interpolation, which implies that they won't touch
// the `Transform` component before the collider is initialized, which in turn means that it will
// always be initialized with the correct `GlobalTransform`.
let parent_global_transform = world
.entity(entity)
.get::<Parent>()
.and_then(|parent| world.entity(parent.get()).get::<GlobalTransform>().copied())
.unwrap_or_default();
let transform = world
.entity(entity)
.get::<Transform>()
.copied()
.unwrap_or_default();
parent_global_transform * transform
};

let scale = global_transform.compute_transform().scale;
#[cfg(feature = "2d")]
let scale = scale.xy();

// Make sure the collider is initialized with the correct scale.
// This overwrites the scale set by the constructor, but that one is
// meant to be only changed after initialization.
world
.entity_mut(entity)
.get_mut::<C>()
.unwrap()
.set_scale(scale.adjust_precision(), 10);

let entity_ref = world.entity(entity);
let collider = entity_ref.get::<C>().unwrap();

let aabb = entity_ref
.get::<ColliderAabb>()
.copied()
Expand Down Expand Up @@ -617,20 +661,22 @@ pub fn update_collider_scale<C: ScalableCollider>(
// Child colliders
Query<(&ColliderTransform, &mut C), (With<Parent>, Changed<ColliderTransform>)>,
)>,
sync_config: Res<SyncConfig>,
) {
// Update collider scale for root bodies
for (transform, mut collider) in &mut colliders.p0() {
#[cfg(feature = "2d")]
let scale = transform.scale.truncate().adjust_precision();
#[cfg(feature = "3d")]
let scale = transform.scale.adjust_precision();
if scale != collider.scale() {
// TODO: Support configurable subdivision count for shapes that
// can't be represented without approximations after scaling.
collider.set_scale(scale, 10);
if sync_config.transform_to_collider_scale {
// Update collider scale for root bodies
for (transform, mut collider) in &mut colliders.p0() {
#[cfg(feature = "2d")]
let scale = transform.scale.truncate().adjust_precision();
#[cfg(feature = "3d")]
let scale = transform.scale.adjust_precision();
if scale != collider.scale() {
// TODO: Support configurable subdivision count for shapes that
// can't be represented without approximations after scaling.
collider.set_scale(scale, 10);
}
}
}

// Update collider scale for child colliders
for (collider_transform, mut collider) in &mut colliders.p1() {
if collider_transform.scale != collider.scale() {
Expand Down
10 changes: 10 additions & 0 deletions src/collision/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,16 @@ impl Contacts {
pub fn total_tangent_force(&self, delta_time: Scalar) -> Vector2 {
self.total_tangent_impulse / delta_time
}

/// Returns `true` if a collision started during the current frame.
pub fn collision_started(&self) -> bool {
!self.during_previous_frame && self.during_current_frame
}

/// Returns `true` if a collision stopped during the current frame.
pub fn collision_stopped(&self) -> bool {
self.during_previous_frame && !self.during_current_frame
}
}

/// A contact manifold between two colliders, containing a set of contact points.
Expand Down
13 changes: 13 additions & 0 deletions src/dynamics/rigid_body/locked_axes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,22 @@ impl LockedAxes {
}

/// Locks translation along the `X` axis.
#[must_use]
pub const fn lock_translation_x(mut self) -> Self {
self.0 |= 0b100_000;
self
}

/// Locks translation along the `Y` axis.
#[must_use]
pub const fn lock_translation_y(mut self) -> Self {
self.0 |= 0b010_000;
self
}

/// Locks translation along the `Z` axis.
#[cfg(feature = "3d")]
#[must_use]
pub const fn lock_translation_z(mut self) -> Self {
self.0 |= 0b001_000;
self
Expand All @@ -89,67 +92,77 @@ impl LockedAxes {

/// Locks rotation around the `Y` axis.
#[cfg(feature = "3d")]
#[must_use]
pub const fn lock_rotation_y(mut self) -> Self {
self.0 |= 0b000_010;
self
}

/// Locks rotation around the `Z` axis.
#[cfg(feature = "3d")]
#[must_use]
pub const fn lock_rotation_z(mut self) -> Self {
self.0 |= 0b000_001;
self
}

/// Locks all rotation.
#[cfg(feature = "2d")]
#[must_use]
pub const fn lock_rotation(mut self) -> Self {
self.0 |= 0b000_001;
self
}

/// Unlocks translation along the `X` axis.
#[must_use]
pub const fn unlock_translation_x(mut self) -> Self {
self.0 &= !0b100_000;
self
}

/// Unlocks translation along the `Y` axis.
#[must_use]
pub const fn unlock_translation_y(mut self) -> Self {
self.0 &= !0b010_000;
self
}

/// Unlocks translation along the `Z` axis.
#[cfg(feature = "3d")]
#[must_use]
pub const fn unlock_translation_z(mut self) -> Self {
self.0 &= !0b001_000;
self
}

/// Unlocks rotation around the `X` axis.
#[cfg(feature = "3d")]
#[must_use]
pub const fn unlock_rotation_x(mut self) -> Self {
self.0 &= !0b000_100;
self
}

/// Unlocks rotation around the `Y` axis.
#[cfg(feature = "3d")]
#[must_use]
pub const fn unlock_rotation_y(mut self) -> Self {
self.0 &= !0b000_010;
self
}

/// Unlocks rotation around the `Z` axis.
#[cfg(feature = "3d")]
#[must_use]
pub const fn unlock_rotation_z(mut self) -> Self {
self.0 &= !0b000_001;
self
}

/// Unlocks all rotation.
#[cfg(feature = "2d")]
#[must_use]
pub const fn unlock_rotation(mut self) -> Self {
self.0 &= !0b000_001;
self
Expand Down
28 changes: 21 additions & 7 deletions src/dynamics/sleeping/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,10 +265,18 @@ fn wake_on_collision_ended(
moved_bodies: Query<Ref<Position>, (Changed<Position>, Without<Sleeping>)>,
colliders: Query<(&ColliderParent, Ref<ColliderTransform>)>,
collisions: Res<Collisions>,
mut sleeping: Query<(Entity, &mut TimeSleeping)>,
mut sleeping: Query<(Entity, &mut TimeSleeping, Has<Sleeping>)>,
) {
// Wake up bodies when a body they're colliding with moves.
for (entity, mut time_sleeping) in &mut sleeping {
for (entity, mut time_sleeping, is_sleeping) in &mut sleeping {
// Skip anything that isn't currently sleeping and already has a time_sleeping of zero.
// We can't gate the sleeping query using With<Sleeping> here because must also reset
// non-zero time_sleeping to 0 when a colliding body moves.
let must_check = is_sleeping || time_sleeping.0 > 0.0;
if !must_check {
continue;
}

// Here we could use CollidingEntities, but it'd be empty if the ContactReportingPlugin was disabled.
let mut colliding_entities = collisions.collisions_with_entity(entity).map(|c| {
if entity == c.entity1 {
Expand All @@ -283,7 +291,9 @@ fn wake_on_collision_ended(
|| moved_bodies.get(p.get()).is_ok_and(|pos| pos.is_changed())
})
}) {
commands.entity(entity).remove::<Sleeping>();
if is_sleeping {
commands.entity(entity).remove::<Sleeping>();
}
time_sleeping.0 = 0.0;
}
}
Expand All @@ -293,12 +303,16 @@ fn wake_on_collision_ended(
if contacts.during_current_frame || !contacts.during_previous_frame {
continue;
}
if let Ok((_, mut time_sleeping)) = sleeping.get_mut(contacts.entity1) {
commands.entity(contacts.entity1).remove::<Sleeping>();
if let Ok((_, mut time_sleeping, is_sleeping)) = sleeping.get_mut(contacts.entity1) {
if is_sleeping {
commands.entity(contacts.entity1).remove::<Sleeping>();
}
time_sleeping.0 = 0.0;
}
if let Ok((_, mut time_sleeping)) = sleeping.get_mut(contacts.entity2) {
commands.entity(contacts.entity2).remove::<Sleeping>();
if let Ok((_, mut time_sleeping, is_sleeping)) = sleeping.get_mut(contacts.entity2) {
if is_sleeping {
commands.entity(contacts.entity2).remove::<Sleeping>();
}
time_sleeping.0 = 0.0;
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/dynamics/solver/joints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,3 +338,10 @@ impl AngleLimit {
None
}
}

/// Disables the joint of the entity it is placed on.
#[derive(Reflect, Clone, Copy, Component, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
#[reflect(Debug, Component)]
pub struct JointDisabled;
2 changes: 1 addition & 1 deletion src/dynamics/solver/xpbd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ pub trait XpbdConstraint<const ENTITY_COUNT: usize>: MapEntities {
pub fn solve_constraint<C: XpbdConstraint<ENTITY_COUNT> + Component, const ENTITY_COUNT: usize>(
mut commands: Commands,
mut bodies: Query<RigidBodyQuery>,
mut constraints: Query<&mut C, Without<RigidBody>>,
mut constraints: Query<&mut C, (Without<RigidBody>, Without<JointDisabled>)>,
time: Res<Time>,
) {
let delta_secs = time.delta_seconds_adjusted();
Expand Down
Loading

0 comments on commit 7134949

Please sign in to comment.