feat: reduce the amount of duplicate work the broad-phase is doing for user changes and CCD + release v0.28.0 (#872)
* feat: reduce the amount of duplicate work the broad-phase is doing for user changes and CCD * Release v0.28.0 * chore: fix warnings * chore: clippy fixes * chore: more clippy fixes
This commit is contained in:
20
CHANGELOG.md
20
CHANGELOG.md
@@ -1,3 +1,23 @@
|
|||||||
|
## v0.28.0 (08 August 2025)
|
||||||
|
|
||||||
|
### Modified
|
||||||
|
|
||||||
|
- Update to nalgebra 0.34 and parry 0.23.
|
||||||
|
- Only run the broad-phase once at the beginning of the physics step.
|
||||||
|
- Don’t rebuild a BVH from scratch for CCD. Instead, reuse the broad-phase bvh with localized changes.
|
||||||
|
- The public methods of `IslandSolver` has changed slightly to take the broad-phase as input.
|
||||||
|
- Removed the `BroadPhase` trait and use the BVH broad-phase directly instead of a trait-object.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add `Collider::compute_broad_phase_aabb` to compute the AABB to be used by the broad-phase, taking
|
||||||
|
into account its contact skin, prediction, and soft-ccd.
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- Fix issue where some solver contacts would disappear from the contact graph before the user
|
||||||
|
had a chance to read them.
|
||||||
|
|
||||||
## v0.27.0 (24 July 2025)
|
## v0.27.0 (24 July 2025)
|
||||||
|
|
||||||
### Modified
|
### Modified
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ other-backends = ["rapier_testbed2d/other-backends"]
|
|||||||
enhanced-determinism = ["rapier2d/enhanced-determinism"]
|
enhanced-determinism = ["rapier2d/enhanced-determinism"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.8"
|
rand = "0.9"
|
||||||
Inflector = "0.11"
|
Inflector = "0.11"
|
||||||
|
|
||||||
[dependencies.rapier_testbed2d]
|
[dependencies.rapier_testbed2d]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use rand::distributions::{Distribution, Standard};
|
use rand::distr::{Distribution, StandardUniform};
|
||||||
use rand::{SeedableRng, rngs::StdRng};
|
use rand::{SeedableRng, rngs::StdRng};
|
||||||
use rapier_testbed2d::Testbed;
|
use rapier_testbed2d::Testbed;
|
||||||
use rapier2d::prelude::*;
|
use rapier2d::prelude::*;
|
||||||
@@ -48,7 +48,7 @@ pub fn init_world(testbed: &mut Testbed) {
|
|||||||
let centery = shift / 2.0;
|
let centery = shift / 2.0;
|
||||||
|
|
||||||
let mut rng = StdRng::seed_from_u64(0);
|
let mut rng = StdRng::seed_from_u64(0);
|
||||||
let distribution = Standard;
|
let distribution = StandardUniform;
|
||||||
|
|
||||||
for i in 0..num {
|
for i in 0..num {
|
||||||
for j in 0usize..num * 5 {
|
for j in 0usize..num * 5 {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ other-backends = ["rapier_testbed3d/other-backends"]
|
|||||||
enhanced-determinism = ["rapier3d/enhanced-determinism"]
|
enhanced-determinism = ["rapier3d/enhanced-determinism"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.8"
|
rand = "0.9"
|
||||||
Inflector = "0.11"
|
Inflector = "0.11"
|
||||||
oorandom = "11"
|
oorandom = "11"
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use rand::distributions::{Distribution, Standard};
|
use rand::distr::{Distribution, StandardUniform};
|
||||||
use rand::{SeedableRng, rngs::StdRng};
|
use rand::{SeedableRng, rngs::StdRng};
|
||||||
use rapier_testbed3d::Testbed;
|
use rapier_testbed3d::Testbed;
|
||||||
use rapier3d::prelude::*;
|
use rapier3d::prelude::*;
|
||||||
@@ -39,7 +39,7 @@ pub fn init_world(testbed: &mut Testbed) {
|
|||||||
let mut offset = -(num as f32) * shift * 0.5;
|
let mut offset = -(num as f32) * shift * 0.5;
|
||||||
|
|
||||||
let mut rng = StdRng::seed_from_u64(0);
|
let mut rng = StdRng::seed_from_u64(0);
|
||||||
let distribution = Standard;
|
let distribution = StandardUniform;
|
||||||
|
|
||||||
for j in 0usize..47 {
|
for j in 0usize..47 {
|
||||||
for i in 0..num {
|
for i in 0..num {
|
||||||
|
|||||||
@@ -51,10 +51,7 @@ pub fn init_world(testbed: &mut Testbed) {
|
|||||||
let t1 = std::time::Instant::now();
|
let t1 = std::time::Instant::now();
|
||||||
let max_toi = ray_ball_radius - 1.0;
|
let max_toi = ray_ball_radius - 1.0;
|
||||||
|
|
||||||
let Some(broad_phase) = physics.broad_phase.downcast_ref::<BroadPhaseBvh>() else {
|
let query_pipeline = physics.broad_phase.as_query_pipeline(
|
||||||
return;
|
|
||||||
};
|
|
||||||
let query_pipeline = broad_phase.as_query_pipeline(
|
|
||||||
physics.narrow_phase.query_dispatcher(),
|
physics.narrow_phase.query_dispatcher(),
|
||||||
&physics.bodies,
|
&physics.bodies,
|
||||||
&physics.colliders,
|
&physics.colliders,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rapier2d-f64"
|
name = "rapier2d-f64"
|
||||||
version = "0.27.0"
|
version = "0.28.0"
|
||||||
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
||||||
description = "2-dimensional physics engine in Rust."
|
description = "2-dimensional physics engine in Rust."
|
||||||
documentation = "https://docs.rs/rapier2d"
|
documentation = "https://docs.rs/rapier2d"
|
||||||
@@ -68,8 +68,8 @@ required-features = ["dim2", "f64"]
|
|||||||
vec_map = { version = "0.8", optional = true }
|
vec_map = { version = "0.8", optional = true }
|
||||||
web-time = { version = "1.1", optional = true }
|
web-time = { version = "1.1", optional = true }
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
nalgebra = "0.33"
|
nalgebra = "0.34"
|
||||||
parry2d-f64 = "0.22.0"
|
parry2d-f64 = "0.23.0"
|
||||||
simba = "0.9"
|
simba = "0.9"
|
||||||
approx = "0.5"
|
approx = "0.5"
|
||||||
rayon = { version = "1", optional = true }
|
rayon = { version = "1", optional = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rapier2d"
|
name = "rapier2d"
|
||||||
version = "0.27.0"
|
version = "0.28.0"
|
||||||
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
||||||
description = "2-dimensional physics engine in Rust."
|
description = "2-dimensional physics engine in Rust."
|
||||||
documentation = "https://docs.rs/rapier2d"
|
documentation = "https://docs.rs/rapier2d"
|
||||||
@@ -69,8 +69,8 @@ required-features = ["dim2", "f32"]
|
|||||||
vec_map = { version = "0.8", optional = true }
|
vec_map = { version = "0.8", optional = true }
|
||||||
web-time = { version = "1.1", optional = true }
|
web-time = { version = "1.1", optional = true }
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
nalgebra = "0.33"
|
nalgebra = "0.34"
|
||||||
parry2d = "0.22.0"
|
parry2d = "0.23.0"
|
||||||
simba = "0.9"
|
simba = "0.9"
|
||||||
approx = "0.5"
|
approx = "0.5"
|
||||||
rayon = { version = "1", optional = true }
|
rayon = { version = "1", optional = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rapier3d-f64"
|
name = "rapier3d-f64"
|
||||||
version = "0.27.0"
|
version = "0.28.0"
|
||||||
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
||||||
description = "3-dimensional physics engine in Rust."
|
description = "3-dimensional physics engine in Rust."
|
||||||
documentation = "https://docs.rs/rapier3d"
|
documentation = "https://docs.rs/rapier3d"
|
||||||
@@ -71,8 +71,8 @@ required-features = ["dim3", "f64"]
|
|||||||
vec_map = { version = "0.8", optional = true }
|
vec_map = { version = "0.8", optional = true }
|
||||||
web-time = { version = "1.1", optional = true }
|
web-time = { version = "1.1", optional = true }
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
nalgebra = "0.33"
|
nalgebra = "0.34"
|
||||||
parry3d-f64 = "0.22.0"
|
parry3d-f64 = "0.23.0"
|
||||||
simba = "0.9"
|
simba = "0.9"
|
||||||
approx = "0.5"
|
approx = "0.5"
|
||||||
rayon = { version = "1", optional = true }
|
rayon = { version = "1", optional = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rapier3d-meshloader"
|
name = "rapier3d-meshloader"
|
||||||
version = "0.8.0"
|
version = "0.9.0"
|
||||||
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
||||||
description = "STL file loader for the 3D rapier physics engine."
|
description = "STL file loader for the 3D rapier physics engine."
|
||||||
documentation = "https://docs.rs/rapier3d-meshloader"
|
documentation = "https://docs.rs/rapier3d-meshloader"
|
||||||
@@ -29,4 +29,4 @@ thiserror = "2"
|
|||||||
profiling = "1.0"
|
profiling = "1.0"
|
||||||
mesh-loader = "0.1.12"
|
mesh-loader = "0.1.12"
|
||||||
|
|
||||||
rapier3d = { version = "0.27.0", path = "../rapier3d" }
|
rapier3d = { version = "0.28.0", path = "../rapier3d" }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rapier3d-urdf"
|
name = "rapier3d-urdf"
|
||||||
version = "0.8.0"
|
version = "0.9.0"
|
||||||
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
||||||
description = "URDF file loader for the 3D rapier physics engine."
|
description = "URDF file loader for the 3D rapier physics engine."
|
||||||
documentation = "https://docs.rs/rapier3d-urdf"
|
documentation = "https://docs.rs/rapier3d-urdf"
|
||||||
@@ -31,5 +31,5 @@ anyhow = "1"
|
|||||||
bitflags = "2"
|
bitflags = "2"
|
||||||
urdf-rs = "0.9"
|
urdf-rs = "0.9"
|
||||||
|
|
||||||
rapier3d = { version = "0.27.0", path = "../rapier3d" }
|
rapier3d = { version = "0.28.0", path = "../rapier3d" }
|
||||||
rapier3d-meshloader = { version = "0.8.0", path = "../rapier3d-meshloader", default-features = false, optional = true }
|
rapier3d-meshloader = { version = "0.9.0", path = "../rapier3d-meshloader", default-features = false, optional = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rapier3d"
|
name = "rapier3d"
|
||||||
version = "0.27.0"
|
version = "0.28.0"
|
||||||
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
||||||
description = "3-dimensional physics engine in Rust."
|
description = "3-dimensional physics engine in Rust."
|
||||||
documentation = "https://docs.rs/rapier3d"
|
documentation = "https://docs.rs/rapier3d"
|
||||||
@@ -73,8 +73,8 @@ required-features = ["dim3", "f32"]
|
|||||||
vec_map = { version = "0.8", optional = true }
|
vec_map = { version = "0.8", optional = true }
|
||||||
web-time = { version = "1.1", optional = true }
|
web-time = { version = "1.1", optional = true }
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
nalgebra = "0.33"
|
nalgebra = "0.34"
|
||||||
parry3d = "0.22.0"
|
parry3d = "0.23.0"
|
||||||
simba = "0.9"
|
simba = "0.9"
|
||||||
approx = "0.5"
|
approx = "0.5"
|
||||||
rayon = { version = "1", optional = true }
|
rayon = { version = "1", optional = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rapier_testbed2d-f64"
|
name = "rapier_testbed2d-f64"
|
||||||
version = "0.27.0"
|
version = "0.28.0"
|
||||||
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
||||||
description = "Testbed for the Rapier 2-dimensional physics engine in Rust."
|
description = "Testbed for the Rapier 2-dimensional physics engine in Rust."
|
||||||
homepage = "http://rapier.rs"
|
homepage = "http://rapier.rs"
|
||||||
@@ -43,9 +43,9 @@ unstable-puffin-pr-235 = []
|
|||||||
features = ["parallel", "profiler_ui"]
|
features = ["parallel", "profiler_ui"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nalgebra = { version = "0.33", features = ["rand", "glam029"] }
|
nalgebra = { version = "0.34", features = ["rand", "glam029"] }
|
||||||
rand = "0.8"
|
rand = "0.9"
|
||||||
rand_pcg = "0.3"
|
rand_pcg = "0.9"
|
||||||
web-time = { version = "1.1" }
|
web-time = { version = "1.1" }
|
||||||
bitflags = "2"
|
bitflags = "2"
|
||||||
num_cpus = { version = "1", optional = true }
|
num_cpus = { version = "1", optional = true }
|
||||||
@@ -98,5 +98,5 @@ bevy = { version = "0.15", default-features = false, features = [
|
|||||||
[dependencies.rapier]
|
[dependencies.rapier]
|
||||||
package = "rapier2d-f64"
|
package = "rapier2d-f64"
|
||||||
path = "../rapier2d-f64"
|
path = "../rapier2d-f64"
|
||||||
version = "0.27.0"
|
version = "0.28.0"
|
||||||
features = ["serde-serialize", "debug-render", "profiler"]
|
features = ["serde-serialize", "debug-render", "profiler"]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rapier_testbed2d"
|
name = "rapier_testbed2d"
|
||||||
version = "0.27.0"
|
version = "0.28.0"
|
||||||
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
||||||
description = "Testbed for the Rapier 2-dimensional physics engine in Rust."
|
description = "Testbed for the Rapier 2-dimensional physics engine in Rust."
|
||||||
homepage = "http://rapier.rs"
|
homepage = "http://rapier.rs"
|
||||||
@@ -43,9 +43,9 @@ unstable-puffin-pr-235 = []
|
|||||||
features = ["parallel", "other-backends", "profiler_ui"]
|
features = ["parallel", "other-backends", "profiler_ui"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nalgebra = { version = "0.33", features = ["rand", "glam029"] }
|
nalgebra = { version = "0.34", features = ["rand", "glam029"] }
|
||||||
rand = "0.8"
|
rand = "0.9"
|
||||||
rand_pcg = "0.3"
|
rand_pcg = "0.9"
|
||||||
web-time = { version = "1.1" }
|
web-time = { version = "1.1" }
|
||||||
bitflags = "2"
|
bitflags = "2"
|
||||||
num_cpus = { version = "1", optional = true }
|
num_cpus = { version = "1", optional = true }
|
||||||
@@ -98,5 +98,5 @@ bevy = { version = "0.15", default-features = false, features = [
|
|||||||
[dependencies.rapier]
|
[dependencies.rapier]
|
||||||
package = "rapier2d"
|
package = "rapier2d"
|
||||||
path = "../rapier2d"
|
path = "../rapier2d"
|
||||||
version = "0.27.0"
|
version = "0.28.0"
|
||||||
features = ["serde-serialize", "debug-render", "profiler"]
|
features = ["serde-serialize", "debug-render", "profiler"]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rapier_testbed3d-f64"
|
name = "rapier_testbed3d-f64"
|
||||||
version = "0.27.0"
|
version = "0.28.0"
|
||||||
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
||||||
description = "Testbed for the Rapier 3-dimensional physics engine in Rust."
|
description = "Testbed for the Rapier 3-dimensional physics engine in Rust."
|
||||||
homepage = "http://rapier.rs"
|
homepage = "http://rapier.rs"
|
||||||
@@ -45,9 +45,9 @@ unstable-puffin-pr-235 = []
|
|||||||
features = ["parallel", "profiler_ui"]
|
features = ["parallel", "profiler_ui"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nalgebra = { version = "0.33", features = ["rand", "glam029"] }
|
nalgebra = { version = "0.34", features = ["rand", "glam029"] }
|
||||||
rand = "0.8"
|
rand = "0.9"
|
||||||
rand_pcg = "0.3"
|
rand_pcg = "0.9"
|
||||||
web-time = { version = "1.1" }
|
web-time = { version = "1.1" }
|
||||||
bitflags = "2"
|
bitflags = "2"
|
||||||
num_cpus = { version = "1", optional = true }
|
num_cpus = { version = "1", optional = true }
|
||||||
@@ -99,5 +99,5 @@ bevy = { version = "0.15", default-features = false, features = [
|
|||||||
[dependencies.rapier]
|
[dependencies.rapier]
|
||||||
package = "rapier3d-f64"
|
package = "rapier3d-f64"
|
||||||
path = "../rapier3d-f64"
|
path = "../rapier3d-f64"
|
||||||
version = "0.27.0"
|
version = "0.28.0"
|
||||||
features = ["serde-serialize", "debug-render", "profiler"]
|
features = ["serde-serialize", "debug-render", "profiler"]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rapier_testbed3d"
|
name = "rapier_testbed3d"
|
||||||
version = "0.27.0"
|
version = "0.28.0"
|
||||||
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
authors = ["Sébastien Crozet <sebcrozet@dimforge.com>"]
|
||||||
description = "Testbed for the Rapier 3-dimensional physics engine in Rust."
|
description = "Testbed for the Rapier 3-dimensional physics engine in Rust."
|
||||||
homepage = "http://rapier.rs"
|
homepage = "http://rapier.rs"
|
||||||
@@ -43,9 +43,9 @@ unstable-puffin-pr-235 = []
|
|||||||
features = ["parallel", "other-backends", "profiler_ui"]
|
features = ["parallel", "other-backends", "profiler_ui"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nalgebra = { version = "0.33", features = ["rand", "glam029"] }
|
nalgebra = { version = "0.34", features = ["rand", "glam029"] }
|
||||||
rand = "0.8"
|
rand = "0.9"
|
||||||
rand_pcg = "0.3"
|
rand_pcg = "0.9"
|
||||||
web-time = { version = "1.1" }
|
web-time = { version = "1.1" }
|
||||||
bitflags = "2"
|
bitflags = "2"
|
||||||
glam = { version = "0.27", optional = true } # For Physx
|
glam = { version = "0.27", optional = true } # For Physx
|
||||||
@@ -97,5 +97,5 @@ bevy = { version = "0.15", default-features = false, features = [
|
|||||||
[dependencies.rapier]
|
[dependencies.rapier]
|
||||||
package = "rapier3d"
|
package = "rapier3d"
|
||||||
path = "../rapier3d"
|
path = "../rapier3d"
|
||||||
version = "0.27.0"
|
version = "0.28.0"
|
||||||
features = ["serde-serialize", "debug-render", "profiler"]
|
features = ["serde-serialize", "debug-render", "profiler"]
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ other-backends = ["rapier_testbed2d/other-backends"]
|
|||||||
enhanced-determinism = ["rapier2d/enhanced-determinism"]
|
enhanced-determinism = ["rapier2d/enhanced-determinism"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.8"
|
rand = "0.9"
|
||||||
lyon = "0.17"
|
lyon = "0.17"
|
||||||
usvg = "0.14"
|
usvg = "0.14"
|
||||||
dot_vox = "5"
|
dot_vox = "5"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use rand::distributions::{Distribution, Standard};
|
use rand::distr::{Distribution, StandardUniform};
|
||||||
use rand::{SeedableRng, rngs::StdRng};
|
use rand::{SeedableRng, rngs::StdRng};
|
||||||
use rapier_testbed2d::Testbed;
|
use rapier_testbed2d::Testbed;
|
||||||
use rapier2d::prelude::*;
|
use rapier2d::prelude::*;
|
||||||
@@ -48,7 +48,7 @@ pub fn init_world(testbed: &mut Testbed) {
|
|||||||
let centery = shift / 2.0;
|
let centery = shift / 2.0;
|
||||||
|
|
||||||
let mut rng = StdRng::seed_from_u64(0);
|
let mut rng = StdRng::seed_from_u64(0);
|
||||||
let distribution = Standard;
|
let distribution = StandardUniform;
|
||||||
|
|
||||||
for i in 0..num {
|
for i in 0..num {
|
||||||
for j in 0usize..num * 4 {
|
for j in 0usize..num * 4 {
|
||||||
|
|||||||
@@ -42,10 +42,7 @@ pub fn init_world(testbed: &mut Testbed) {
|
|||||||
testbed.add_callback(move |mut graphics, physics, _, run| {
|
testbed.add_callback(move |mut graphics, physics, _, run| {
|
||||||
let slow_time = run.timestep_id as f32 / 3.0;
|
let slow_time = run.timestep_id as f32 / 3.0;
|
||||||
|
|
||||||
let Some(broad_phase) = physics.broad_phase.downcast_ref::<BroadPhaseBvh>() else {
|
let query_pipeline = physics.broad_phase.as_query_pipeline(
|
||||||
return;
|
|
||||||
};
|
|
||||||
let query_pipeline = broad_phase.as_query_pipeline(
|
|
||||||
physics.narrow_phase.query_dispatcher(),
|
physics.narrow_phase.query_dispatcher(),
|
||||||
&physics.bodies,
|
&physics.bodies,
|
||||||
&physics.colliders,
|
&physics.colliders,
|
||||||
|
|||||||
@@ -137,10 +137,7 @@ fn update_kinematic_controller(
|
|||||||
let character_shape = character_collider.shared_shape().clone();
|
let character_shape = character_collider.shared_shape().clone();
|
||||||
let character_mass = character_body.mass();
|
let character_mass = character_body.mass();
|
||||||
|
|
||||||
let Some(broad_phase) = phx.broad_phase.downcast_ref::<BroadPhaseBvh>() else {
|
let mut query_pipeline = phx.broad_phase.as_query_pipeline_mut(
|
||||||
return;
|
|
||||||
};
|
|
||||||
let mut query_pipeline = broad_phase.as_query_pipeline_mut(
|
|
||||||
phx.narrow_phase.query_dispatcher(),
|
phx.narrow_phase.query_dispatcher(),
|
||||||
&mut phx.bodies,
|
&mut phx.bodies,
|
||||||
&mut phx.colliders,
|
&mut phx.colliders,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ simd-nightly = ["rapier3d-f64/simd-nightly"]
|
|||||||
enhanced-determinism = ["rapier3d-f64/enhanced-determinism"]
|
enhanced-determinism = ["rapier3d-f64/enhanced-determinism"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.8"
|
rand = "0.9"
|
||||||
getrandom = { version = "0.2", features = ["js"] }
|
getrandom = { version = "0.2", features = ["js"] }
|
||||||
wasm-bindgen = "0.2"
|
wasm-bindgen = "0.2"
|
||||||
obj-rs = { version = "0.7", default-features = false }
|
obj-rs = { version = "0.7", default-features = false }
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ pub fn init_world(testbed: &mut Testbed) {
|
|||||||
state.multibody_joints,
|
state.multibody_joints,
|
||||||
);
|
);
|
||||||
testbed.harness_mut().physics.islands = state.islands;
|
testbed.harness_mut().physics.islands = state.islands;
|
||||||
testbed.harness_mut().physics.broad_phase = Box::new(state.broad_phase);
|
testbed.harness_mut().physics.broad_phase = state.broad_phase;
|
||||||
testbed.harness_mut().physics.narrow_phase = state.narrow_phase;
|
testbed.harness_mut().physics.narrow_phase = state.narrow_phase;
|
||||||
testbed.harness_mut().physics.ccd_solver = state.ccd_solver;
|
testbed.harness_mut().physics.ccd_solver = state.ccd_solver;
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ other-backends = ["rapier_testbed3d/other-backends"]
|
|||||||
enhanced-determinism = ["rapier3d/enhanced-determinism"]
|
enhanced-determinism = ["rapier3d/enhanced-determinism"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.8"
|
rand = "0.9"
|
||||||
getrandom = { version = "0.2", features = ["js"] }
|
getrandom = { version = "0.2", features = ["js"] }
|
||||||
wasm-bindgen = "0.2"
|
wasm-bindgen = "0.2"
|
||||||
obj-rs = { version = "0.7", default-features = false }
|
obj-rs = { version = "0.7", default-features = false }
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ mod convex_polyhedron3;
|
|||||||
mod damping3;
|
mod damping3;
|
||||||
mod debug_add_remove_collider3;
|
mod debug_add_remove_collider3;
|
||||||
mod debug_articulations3;
|
mod debug_articulations3;
|
||||||
|
mod debug_balls3;
|
||||||
mod debug_big_colliders3;
|
mod debug_big_colliders3;
|
||||||
mod debug_boxes3;
|
mod debug_boxes3;
|
||||||
mod debug_cylinder3;
|
mod debug_cylinder3;
|
||||||
@@ -101,6 +102,7 @@ pub fn main() {
|
|||||||
),
|
),
|
||||||
("(Debug) big colliders", debug_big_colliders3::init_world),
|
("(Debug) big colliders", debug_big_colliders3::init_world),
|
||||||
("(Debug) boxes", debug_boxes3::init_world),
|
("(Debug) boxes", debug_boxes3::init_world),
|
||||||
|
("(Debug) balls", debug_balls3::init_world),
|
||||||
("(Debug) pop", debug_pop3::init_world),
|
("(Debug) pop", debug_pop3::init_world),
|
||||||
(
|
(
|
||||||
"(Debug) dyn. coll. add",
|
"(Debug) dyn. coll. add",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use rand::distributions::{Distribution, Standard};
|
use rand::distr::{Distribution, StandardUniform};
|
||||||
use rand::{SeedableRng, rngs::StdRng};
|
use rand::{SeedableRng, rngs::StdRng};
|
||||||
use rapier_testbed3d::Testbed;
|
use rapier_testbed3d::Testbed;
|
||||||
use rapier3d::prelude::*;
|
use rapier3d::prelude::*;
|
||||||
@@ -36,7 +36,7 @@ pub fn init_world(testbed: &mut Testbed) {
|
|||||||
let centerz = shift * (num / 2) as f32;
|
let centerz = shift * (num / 2) as f32;
|
||||||
|
|
||||||
let mut rng = StdRng::seed_from_u64(0);
|
let mut rng = StdRng::seed_from_u64(0);
|
||||||
let distribution = Standard;
|
let distribution = StandardUniform;
|
||||||
|
|
||||||
for j in 0usize..25 {
|
for j in 0usize..25 {
|
||||||
for i in 0..num {
|
for i in 0..num {
|
||||||
|
|||||||
59
examples3d/debug_balls3.rs
Normal file
59
examples3d/debug_balls3.rs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
use rapier_testbed3d::Testbed;
|
||||||
|
use rapier3d::prelude::*;
|
||||||
|
|
||||||
|
pub fn init_world(testbed: &mut Testbed) {
|
||||||
|
/*
|
||||||
|
* World
|
||||||
|
*/
|
||||||
|
let mut bodies = RigidBodySet::new();
|
||||||
|
let mut colliders = ColliderSet::new();
|
||||||
|
let impulse_joints = ImpulseJointSet::new();
|
||||||
|
let multibody_joints = MultibodyJointSet::new();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the balls
|
||||||
|
*/
|
||||||
|
let num_j = 10;
|
||||||
|
let num_ik = 10;
|
||||||
|
let rad = 0.5;
|
||||||
|
|
||||||
|
let shift = rad * 2.0;
|
||||||
|
let centerx = shift * (num_ik as f32) / 2.0;
|
||||||
|
let centery = shift / 2.0;
|
||||||
|
let centerz = shift * (num_ik as f32) / 2.0;
|
||||||
|
|
||||||
|
for i in 0..num_ik {
|
||||||
|
for j in 0usize..num_j {
|
||||||
|
for k in 0..num_ik {
|
||||||
|
let x = i as f32 * shift - centerx;
|
||||||
|
let z = k as f32 * shift - centerz;
|
||||||
|
|
||||||
|
let status = if j == 0 || i == 0 || k == 0 || i == num_ik - 1 || k == num_ik - 1 {
|
||||||
|
RigidBodyType::Fixed
|
||||||
|
} else {
|
||||||
|
RigidBodyType::Dynamic
|
||||||
|
};
|
||||||
|
|
||||||
|
let y = if status.is_fixed() {
|
||||||
|
j as f32 * shift + centery
|
||||||
|
} else {
|
||||||
|
j as f32 * shift * 2.0 + centery
|
||||||
|
};
|
||||||
|
|
||||||
|
// Build the rigid body.
|
||||||
|
let rigid_body = RigidBodyBuilder::new(status)
|
||||||
|
.translation(vector![x, y, z])
|
||||||
|
.can_sleep(false);
|
||||||
|
let handle = bodies.insert(rigid_body);
|
||||||
|
let collider = ColliderBuilder::ball(rad).friction(0.0);
|
||||||
|
colliders.insert_with_parent(collider, handle, &mut bodies);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up the testbed.
|
||||||
|
*/
|
||||||
|
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
|
||||||
|
testbed.look_at(point![100.0, 100.0, 100.0], Point::origin());
|
||||||
|
}
|
||||||
@@ -54,7 +54,7 @@ pub fn init_world(testbed: &mut Testbed) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
testbed.harness_mut().physics.islands = state.islands;
|
testbed.harness_mut().physics.islands = state.islands;
|
||||||
testbed.harness_mut().physics.broad_phase = Box::new(state.broad_phase);
|
testbed.harness_mut().physics.broad_phase = state.broad_phase;
|
||||||
testbed.harness_mut().physics.narrow_phase = state.narrow_phase;
|
testbed.harness_mut().physics.narrow_phase = state.narrow_phase;
|
||||||
testbed.harness_mut().physics.integration_parameters = state.integration_parameters;
|
testbed.harness_mut().physics.integration_parameters = state.integration_parameters;
|
||||||
testbed.harness_mut().physics.gravity = state.gravity;
|
testbed.harness_mut().physics.gravity = state.gravity;
|
||||||
|
|||||||
@@ -147,10 +147,7 @@ fn update_kinematic_controller(
|
|||||||
let character_shape = character_collider.shared_shape().clone();
|
let character_shape = character_collider.shared_shape().clone();
|
||||||
let character_mass = character_body.mass();
|
let character_mass = character_body.mass();
|
||||||
|
|
||||||
let Some(broad_phase) = phx.broad_phase.downcast_ref::<BroadPhaseBvh>() else {
|
let mut query_pipeline = phx.broad_phase.as_query_pipeline_mut(
|
||||||
return;
|
|
||||||
};
|
|
||||||
let mut query_pipeline = broad_phase.as_query_pipeline_mut(
|
|
||||||
phx.narrow_phase.query_dispatcher(),
|
phx.narrow_phase.query_dispatcher(),
|
||||||
&mut phx.bodies,
|
&mut phx.bodies,
|
||||||
&mut phx.colliders,
|
&mut phx.colliders,
|
||||||
|
|||||||
@@ -211,10 +211,7 @@ pub fn init_world(testbed: &mut Testbed) {
|
|||||||
predicate: Some(&|_, co: &Collider| co.shape().as_voxels().is_some()),
|
predicate: Some(&|_, co: &Collider| co.shape().as_voxels().is_some()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let Some(broad_phase) = physics.broad_phase.downcast_ref::<BroadPhaseBvh>() else {
|
let query_pipeline = physics.broad_phase.as_query_pipeline(
|
||||||
return;
|
|
||||||
};
|
|
||||||
let query_pipeline = broad_phase.as_query_pipeline(
|
|
||||||
physics.narrow_phase.query_dispatcher(),
|
physics.narrow_phase.query_dispatcher(),
|
||||||
&physics.bodies,
|
&physics.bodies,
|
||||||
&physics.colliders,
|
&physics.colliders,
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
if [[ "$PUBLISH_MODE" == 1 ]]
|
if [[ "$PUBLISH_MODE" == 1 ]]
|
||||||
then
|
then
|
||||||
./scripts/publish-rapier.sh &&
|
./scripts/publish-rapier.sh &&
|
||||||
./scripts/publish-testbeds.sh &&
|
./scripts/publish-extra-formats.sh &&
|
||||||
./scripts/publish-extra-formats.sh
|
./scripts/publish-testbeds.sh
|
||||||
else
|
else
|
||||||
echo "Running in dry mode, re-run with \`PUBLISH_MODE=1 publish-all.sh\` to actually publish."
|
echo "Running in dry mode, re-run with \`PUBLISH_MODE=1 publish-all.sh\` to actually publish."
|
||||||
|
|
||||||
DRY_RUN="--dry-run" ./scripts/publish-rapier.sh &&
|
DRY_RUN="--dry-run" ./scripts/publish-rapier.sh &&
|
||||||
DRY_RUN="--dry-run" ./scripts/publish-testbeds.sh &&
|
DRY_RUN="--dry-run" ./scripts/publish-extra-formats.sh &&
|
||||||
DRY_RUN="--dry-run" ./scripts/publish-extra-formats.sh
|
DRY_RUN="--dry-run" ./scripts/publish-testbeds.sh
|
||||||
fi
|
fi
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
use super::TOIEntry;
|
use super::TOIEntry;
|
||||||
use crate::dynamics::{IslandManager, RigidBodyHandle, RigidBodySet};
|
use crate::dynamics::{IntegrationParameters, IslandManager, RigidBodyHandle, RigidBodySet};
|
||||||
use crate::geometry::{ColliderParent, ColliderSet, CollisionEvent, NarrowPhase};
|
use crate::geometry::{BroadPhaseBvh, ColliderParent, ColliderSet, CollisionEvent, NarrowPhase};
|
||||||
use crate::math::Real;
|
use crate::math::Real;
|
||||||
use crate::parry::utils::SortedPair;
|
use crate::parry::utils::SortedPair;
|
||||||
use crate::pipeline::{EventHandler, QueryFilter, QueryPipeline};
|
use crate::pipeline::{EventHandler, QueryFilter};
|
||||||
use crate::prelude::{ActiveEvents, CollisionEventFlags};
|
use crate::prelude::{ActiveEvents, CollisionEventFlags};
|
||||||
use parry::partitioning::{Bvh, BvhBuildStrategy};
|
|
||||||
use parry::utils::hashmap::HashMap;
|
use parry::utils::hashmap::HashMap;
|
||||||
use std::collections::BinaryHeap;
|
use std::collections::BinaryHeap;
|
||||||
|
|
||||||
@@ -16,26 +15,14 @@ pub enum PredictedImpacts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Solver responsible for performing motion-clamping on fast-moving bodies.
|
/// Solver responsible for performing motion-clamping on fast-moving bodies.
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default)]
|
||||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||||
pub struct CCDSolver {
|
pub struct CCDSolver;
|
||||||
// TODO PERF: for now the CCD solver maintains its own bvh for CCD queries.
|
|
||||||
// At each frame it get rebuilt.
|
|
||||||
// We should consider an alternative to directly use the broad-phase’s.
|
|
||||||
#[cfg_attr(feature = "serde-serialize", serde(skip))]
|
|
||||||
bvh: Bvh,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for CCDSolver {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CCDSolver {
|
impl CCDSolver {
|
||||||
/// Initializes a new CCD solver
|
/// Initializes a new CCD solver
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { bvh: Bvh::new() }
|
Self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply motion-clamping to the bodies affected by the given `impacts`.
|
/// Apply motion-clamping to the bodies affected by the given `impacts`.
|
||||||
@@ -101,42 +88,35 @@ impl CCDSolver {
|
|||||||
#[profiling::function]
|
#[profiling::function]
|
||||||
pub fn find_first_impact(
|
pub fn find_first_impact(
|
||||||
&mut self,
|
&mut self,
|
||||||
dt: Real,
|
dt: Real, // NOTE: this doesn’t necessarily match the `params.dt`.
|
||||||
|
params: &IntegrationParameters,
|
||||||
islands: &IslandManager,
|
islands: &IslandManager,
|
||||||
bodies: &RigidBodySet,
|
bodies: &RigidBodySet,
|
||||||
colliders: &ColliderSet,
|
colliders: &ColliderSet,
|
||||||
|
broad_phase: &mut BroadPhaseBvh,
|
||||||
narrow_phase: &NarrowPhase,
|
narrow_phase: &NarrowPhase,
|
||||||
) -> Option<Real> {
|
) -> Option<Real> {
|
||||||
// Update the query pipeline with the colliders’ predicted positions.
|
// Update the query pipeline with the colliders’ predicted positions.
|
||||||
self.bvh = Bvh::from_iter(
|
for (handle, co) in colliders.iter_enabled() {
|
||||||
BvhBuildStrategy::Binned,
|
if let Some(co_parent) = co.parent {
|
||||||
colliders.iter_enabled().map(|(co_handle, co)| {
|
let rb = &bodies[co_parent.handle];
|
||||||
let id = co_handle.into_raw_parts().0;
|
if rb.is_ccd_active() {
|
||||||
if let Some(co_parent) = co.parent {
|
|
||||||
let rb = &bodies[co_parent.handle];
|
|
||||||
let predicted_pos = rb
|
let predicted_pos = rb
|
||||||
.pos
|
.pos
|
||||||
.integrate_forces_and_velocities(dt, &rb.forces, &rb.vels, &rb.mprops);
|
.integrate_forces_and_velocities(dt, &rb.forces, &rb.vels, &rb.mprops);
|
||||||
|
|
||||||
let next_position = predicted_pos * co_parent.pos_wrt_parent;
|
let next_position = predicted_pos * co_parent.pos_wrt_parent;
|
||||||
(
|
let swept_aabb = co.shape.compute_swept_aabb(&co.pos, &next_position);
|
||||||
id as usize,
|
broad_phase.set_aabb(params, handle, swept_aabb);
|
||||||
co.shape.compute_swept_aabb(&co.pos, &next_position),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(id as usize, co.shape.compute_aabb(&co.pos))
|
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
);
|
}
|
||||||
|
|
||||||
let query_pipeline = QueryPipeline {
|
let query_pipeline = broad_phase.as_query_pipeline(
|
||||||
// NOTE: the upcast needs at least rust 1.86
|
narrow_phase.query_dispatcher(),
|
||||||
dispatcher: narrow_phase.query_dispatcher(),
|
|
||||||
bvh: &self.bvh,
|
|
||||||
bodies,
|
bodies,
|
||||||
colliders,
|
colliders,
|
||||||
filter: QueryFilter::default(),
|
QueryFilter::default(),
|
||||||
};
|
);
|
||||||
|
|
||||||
let mut pairs_seen = HashMap::default();
|
let mut pairs_seen = HashMap::default();
|
||||||
let mut min_toi = dt;
|
let mut min_toi = dt;
|
||||||
@@ -234,43 +214,39 @@ impl CCDSolver {
|
|||||||
#[profiling::function]
|
#[profiling::function]
|
||||||
pub fn predict_impacts_at_next_positions(
|
pub fn predict_impacts_at_next_positions(
|
||||||
&mut self,
|
&mut self,
|
||||||
dt: Real,
|
params: &IntegrationParameters,
|
||||||
islands: &IslandManager,
|
islands: &IslandManager,
|
||||||
bodies: &RigidBodySet,
|
bodies: &RigidBodySet,
|
||||||
colliders: &ColliderSet,
|
colliders: &ColliderSet,
|
||||||
|
broad_phase: &mut BroadPhaseBvh,
|
||||||
narrow_phase: &NarrowPhase,
|
narrow_phase: &NarrowPhase,
|
||||||
events: &dyn EventHandler,
|
events: &dyn EventHandler,
|
||||||
) -> PredictedImpacts {
|
) -> PredictedImpacts {
|
||||||
|
let dt = params.dt;
|
||||||
let mut frozen = HashMap::<_, Real>::default();
|
let mut frozen = HashMap::<_, Real>::default();
|
||||||
let mut all_toi = BinaryHeap::new();
|
let mut all_toi = BinaryHeap::new();
|
||||||
let mut pairs_seen = HashMap::default();
|
let mut pairs_seen = HashMap::default();
|
||||||
let mut min_overstep = dt;
|
let mut min_overstep = dt;
|
||||||
|
|
||||||
// Update the query pipeline with the colliders’ `next_position`.
|
// Update the query pipeline with the colliders’ `next_position`.
|
||||||
self.bvh = Bvh::from_iter(
|
for (handle, co) in colliders.iter_enabled() {
|
||||||
BvhBuildStrategy::Binned,
|
if let Some(co_parent) = co.parent {
|
||||||
colliders.iter_enabled().map(|(co_handle, co)| {
|
let rb = &bodies[co_parent.handle];
|
||||||
let id = co_handle.into_raw_parts().0;
|
if rb.is_ccd_active() {
|
||||||
if let Some(co_parent) = co.parent {
|
|
||||||
let rb_next_pos = &bodies[co_parent.handle].pos.next_position;
|
let rb_next_pos = &bodies[co_parent.handle].pos.next_position;
|
||||||
let next_position = rb_next_pos * co_parent.pos_wrt_parent;
|
let next_position = rb_next_pos * co_parent.pos_wrt_parent;
|
||||||
(
|
let swept_aabb = co.shape.compute_swept_aabb(&co.pos, &next_position);
|
||||||
id as usize,
|
broad_phase.set_aabb(params, handle, swept_aabb);
|
||||||
co.shape.compute_swept_aabb(&co.pos, &next_position),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(id as usize, co.shape.compute_aabb(&co.pos))
|
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
);
|
}
|
||||||
|
|
||||||
let query_pipeline = QueryPipeline {
|
let query_pipeline = broad_phase.as_query_pipeline(
|
||||||
dispatcher: narrow_phase.query_dispatcher(),
|
narrow_phase.query_dispatcher(),
|
||||||
bvh: &self.bvh,
|
|
||||||
bodies,
|
bodies,
|
||||||
colliders,
|
colliders,
|
||||||
filter: QueryFilter::default(),
|
QueryFilter::default(),
|
||||||
};
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
use crate::dynamics::RigidBodySet;
|
|
||||||
use crate::geometry::{BroadPhasePairEvent, ColliderHandle, ColliderSet};
|
|
||||||
use crate::prelude::IntegrationParameters;
|
|
||||||
use downcast_rs::DowncastSync;
|
|
||||||
|
|
||||||
/// Trait implemented by broad-phase algorithms supported by Rapier.
|
|
||||||
///
|
|
||||||
/// The task of a broad-phase algorithm is to detect potential collision pairs, usually based on
|
|
||||||
/// bounding volumes. The pairs must be conservative: it is OK to create a collision pair if
|
|
||||||
/// two objects don’t actually touch, but it is incorrect to remove a pair between two objects
|
|
||||||
/// that are still touching. In other words, it can have false-positive (though these induce
|
|
||||||
/// some computational overhead on the narrow-phase), but cannot have false-negative.
|
|
||||||
pub trait BroadPhase: Send + Sync + 'static + DowncastSync {
|
|
||||||
/// Updates the broad-phase.
|
|
||||||
///
|
|
||||||
/// The results must be output through the `events` struct. The broad-phase algorithm is only
|
|
||||||
/// required to generate new events (i.e. no need to re-send an `AddPair` event if it was already
|
|
||||||
/// sent previously and no `RemovePair` happened since then). Sending redundant events is allowed
|
|
||||||
/// but can result in a slight computational overhead.
|
|
||||||
///
|
|
||||||
/// The `colliders` set is mutable only to provide access to
|
|
||||||
/// [`collider.set_internal_broad_phase_proxy_index`]. Other properties of the collider should
|
|
||||||
/// **not** be modified during the broad-phase update.
|
|
||||||
///
|
|
||||||
/// # Parameters
|
|
||||||
/// - `params`: the integration parameters governing the simulation.
|
|
||||||
/// - `colliders`: the set of colliders. Change detection with `collider.needs_broad_phase_update()`
|
|
||||||
/// can be relied on at this stage.
|
|
||||||
/// - `modified_colliders`: colliders that are know to be modified since the last update.
|
|
||||||
/// - `removed_colliders`: colliders that got removed since the last update. Any associated data
|
|
||||||
/// in the broad-phase should be removed by this call to `update`.
|
|
||||||
/// - `events`: the broad-phase’s output. They indicate what collision pairs need to be created
|
|
||||||
/// and what pairs need to be removed. It is OK to create pairs for colliders that don’t
|
|
||||||
/// actually collide (though this can increase computational overhead in the narrow-phase)
|
|
||||||
/// but it is important not to indicate removal of a collision pair if the underlying colliders
|
|
||||||
/// are still touching or closer than `prediction_distance`.
|
|
||||||
fn update(
|
|
||||||
&mut self,
|
|
||||||
params: &IntegrationParameters,
|
|
||||||
colliders: &ColliderSet,
|
|
||||||
bodies: &RigidBodySet,
|
|
||||||
modified_colliders: &[ColliderHandle],
|
|
||||||
removed_colliders: &[ColliderHandle],
|
|
||||||
events: &mut Vec<BroadPhasePairEvent>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
downcast_rs::impl_downcast!(sync BroadPhase);
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::dynamics::{IntegrationParameters, RigidBodySet};
|
use crate::dynamics::{IntegrationParameters, RigidBodySet};
|
||||||
use crate::geometry::{BroadPhase, BroadPhasePairEvent, ColliderHandle, ColliderPair, ColliderSet};
|
use crate::geometry::{Aabb, BroadPhasePairEvent, ColliderHandle, ColliderPair, ColliderSet};
|
||||||
use parry::bounding_volume::BoundingVolume;
|
use crate::math::Real;
|
||||||
use parry::partitioning::{Bvh, BvhWorkspace};
|
use parry::partitioning::{Bvh, BvhWorkspace};
|
||||||
use parry::utils::hashmap::{Entry, HashMap};
|
use parry::utils::hashmap::{Entry, HashMap};
|
||||||
|
|
||||||
@@ -36,6 +36,9 @@ pub enum BvhOptimizationStrategy {
|
|||||||
const ENABLE_TREE_VALIDITY_CHECK: bool = false;
|
const ENABLE_TREE_VALIDITY_CHECK: bool = false;
|
||||||
|
|
||||||
impl BroadPhaseBvh {
|
impl BroadPhaseBvh {
|
||||||
|
const CHANGE_DETECTION_ENABLED: bool = true;
|
||||||
|
const CHANGE_DETECTION_FACTOR: Real = 1.0e-2;
|
||||||
|
|
||||||
/// Initializes a new empty broad-phase.
|
/// Initializes a new empty broad-phase.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
@@ -50,7 +53,30 @@ impl BroadPhaseBvh {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_with_strategy(
|
/// Updates the broad-phase.
|
||||||
|
///
|
||||||
|
/// The results are output through the `events` struct. The broad-phase algorithm is only
|
||||||
|
/// required to generate new events (i.e. no need to re-send an `AddPair` event if it was already
|
||||||
|
/// sent previously and no `RemovePair` happened since then). Sending redundant events is allowed
|
||||||
|
/// but can result in a slight computational overhead.
|
||||||
|
///
|
||||||
|
/// The `colliders` set is mutable only to provide access to
|
||||||
|
/// [`collider.set_internal_broad_phase_proxy_index`]. Other properties of the collider should
|
||||||
|
/// **not** be modified during the broad-phase update.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - `params`: the integration parameters governing the simulation.
|
||||||
|
/// - `colliders`: the set of colliders. Change detection with `collider.needs_broad_phase_update()`
|
||||||
|
/// can be relied on at this stage.
|
||||||
|
/// - `modified_colliders`: colliders that are know to be modified since the last update.
|
||||||
|
/// - `removed_colliders`: colliders that got removed since the last update. Any associated data
|
||||||
|
/// in the broad-phase should be removed by this call to `update`.
|
||||||
|
/// - `events`: the broad-phase’s output. They indicate what collision pairs need to be created
|
||||||
|
/// and what pairs need to be removed. It is OK to create pairs for colliders that don’t
|
||||||
|
/// actually collide (though this can increase computational overhead in the narrow-phase)
|
||||||
|
/// but it is important not to indicate removal of a collision pair if the underlying colliders
|
||||||
|
/// are still touching or closer than `prediction_distance`.
|
||||||
|
pub fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
params: &IntegrationParameters,
|
params: &IntegrationParameters,
|
||||||
colliders: &ColliderSet,
|
colliders: &ColliderSet,
|
||||||
@@ -58,10 +84,7 @@ impl BroadPhaseBvh {
|
|||||||
modified_colliders: &[ColliderHandle],
|
modified_colliders: &[ColliderHandle],
|
||||||
removed_colliders: &[ColliderHandle],
|
removed_colliders: &[ColliderHandle],
|
||||||
events: &mut Vec<BroadPhasePairEvent>,
|
events: &mut Vec<BroadPhasePairEvent>,
|
||||||
strategy: BvhOptimizationStrategy,
|
|
||||||
) {
|
) {
|
||||||
const CHANGE_DETECTION_ENABLED: bool = true;
|
|
||||||
|
|
||||||
self.frame_index = self.frame_index.overflowing_add(1).0;
|
self.frame_index = self.frame_index.overflowing_add(1).0;
|
||||||
|
|
||||||
// Removals must be handled first, in case another collider in
|
// Removals must be handled first, in case another collider in
|
||||||
@@ -70,9 +93,9 @@ impl BroadPhaseBvh {
|
|||||||
self.tree.remove(handle.into_raw_parts().0);
|
self.tree.remove(handle.into_raw_parts().0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if modified_colliders.is_empty() {
|
// if modified_colliders.is_empty() {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
let first_pass = self.tree.is_empty();
|
let first_pass = self.tree.is_empty();
|
||||||
|
|
||||||
@@ -83,29 +106,10 @@ impl BroadPhaseBvh {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take soft-ccd into account by growing the aabb.
|
let aabb = collider.compute_broad_phase_aabb(params, bodies);
|
||||||
let next_pose = collider.parent.and_then(|p| {
|
|
||||||
let parent = bodies.get(p.handle)?;
|
|
||||||
(parent.soft_ccd_prediction() > 0.0).then(|| {
|
|
||||||
parent.predict_position_using_velocity_and_forces_with_max_dist(
|
|
||||||
params.dt,
|
|
||||||
parent.soft_ccd_prediction(),
|
|
||||||
) * p.pos_wrt_parent
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
let prediction_distance = params.prediction_distance();
|
let change_detection_skin = if Self::CHANGE_DETECTION_ENABLED {
|
||||||
let mut aabb = collider.compute_collision_aabb(prediction_distance / 2.0);
|
Self::CHANGE_DETECTION_FACTOR * params.length_unit
|
||||||
if let Some(next_pose) = next_pose {
|
|
||||||
let next_aabb = collider
|
|
||||||
.shape
|
|
||||||
.compute_aabb(&next_pose)
|
|
||||||
.loosened(collider.contact_skin() + prediction_distance / 2.0);
|
|
||||||
aabb.merge(&next_aabb);
|
|
||||||
}
|
|
||||||
|
|
||||||
let change_detection_skin = if CHANGE_DETECTION_ENABLED {
|
|
||||||
1.0e-2 * params.length_unit
|
|
||||||
} else {
|
} else {
|
||||||
0.0
|
0.0
|
||||||
};
|
};
|
||||||
@@ -127,7 +131,7 @@ impl BroadPhaseBvh {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// let t0 = std::time::Instant::now();
|
// let t0 = std::time::Instant::now();
|
||||||
match strategy {
|
match self.optimization_strategy {
|
||||||
BvhOptimizationStrategy::SubtreeOptimizer => {
|
BvhOptimizationStrategy::SubtreeOptimizer => {
|
||||||
self.tree.optimize_incremental(&mut self.workspace);
|
self.tree.optimize_incremental(&mut self.workspace);
|
||||||
}
|
}
|
||||||
@@ -190,7 +194,7 @@ impl BroadPhaseBvh {
|
|||||||
|
|
||||||
// let t0 = std::time::Instant::now();
|
// let t0 = std::time::Instant::now();
|
||||||
self.tree
|
self.tree
|
||||||
.traverse_bvtt_single_tree::<CHANGE_DETECTION_ENABLED>(
|
.traverse_bvtt_single_tree::<{ Self::CHANGE_DETECTION_ENABLED }>(
|
||||||
&mut self.workspace,
|
&mut self.workspace,
|
||||||
&mut pairs_collector,
|
&mut pairs_collector,
|
||||||
);
|
);
|
||||||
@@ -220,7 +224,7 @@ impl BroadPhaseBvh {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!CHANGE_DETECTION_ENABLED || node0.is_changed() || node1.is_changed())
|
if (!Self::CHANGE_DETECTION_ENABLED || node0.is_changed() || node1.is_changed())
|
||||||
&& !node0.intersects(node1)
|
&& !node0.intersects(node1)
|
||||||
{
|
{
|
||||||
events.push(BroadPhasePairEvent::DeletePair(ColliderPair::new(*h0, *h1)));
|
events.push(BroadPhasePairEvent::DeletePair(ColliderPair::new(*h0, *h1)));
|
||||||
@@ -245,26 +249,21 @@ impl BroadPhaseBvh {
|
|||||||
// removed_pairs
|
// removed_pairs
|
||||||
// );
|
// );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl BroadPhase for BroadPhaseBvh {
|
/// Sets the AABB associated to the given collider.
|
||||||
fn update(
|
///
|
||||||
&mut self,
|
/// The AABB change will be immediately applied and propagated through the underlying BVH.
|
||||||
params: &IntegrationParameters,
|
/// Change detection will automatically take it into account during the next broad-phase update.
|
||||||
colliders: &ColliderSet,
|
pub fn set_aabb(&mut self, params: &IntegrationParameters, handle: ColliderHandle, aabb: Aabb) {
|
||||||
bodies: &RigidBodySet,
|
let change_detection_skin = if Self::CHANGE_DETECTION_ENABLED {
|
||||||
modified_colliders: &[ColliderHandle],
|
Self::CHANGE_DETECTION_FACTOR * params.length_unit
|
||||||
removed_colliders: &[ColliderHandle],
|
} else {
|
||||||
events: &mut Vec<BroadPhasePairEvent>,
|
0.0
|
||||||
) {
|
};
|
||||||
self.update_with_strategy(
|
self.tree.insert_with_change_detection(
|
||||||
params,
|
aabb,
|
||||||
colliders,
|
handle.into_raw_parts().0,
|
||||||
bodies,
|
change_detection_skin,
|
||||||
modified_colliders,
|
|
||||||
removed_colliders,
|
|
||||||
events,
|
|
||||||
self.optimization_strategy,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle};
|
use crate::dynamics::{CoefficientCombineRule, MassProperties, RigidBodyHandle, RigidBodySet};
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
use crate::geometry::HeightFieldFlags;
|
use crate::geometry::HeightFieldFlags;
|
||||||
use crate::geometry::{
|
use crate::geometry::{
|
||||||
@@ -9,7 +9,7 @@ use crate::geometry::{
|
|||||||
use crate::math::{AngVector, DIM, Isometry, Point, Real, Rotation, Vector};
|
use crate::math::{AngVector, DIM, Isometry, Point, Real, Rotation, Vector};
|
||||||
use crate::parry::transformation::vhacd::VHACDParameters;
|
use crate::parry::transformation::vhacd::VHACDParameters;
|
||||||
use crate::pipeline::{ActiveEvents, ActiveHooks};
|
use crate::pipeline::{ActiveEvents, ActiveHooks};
|
||||||
use crate::prelude::ColliderEnabled;
|
use crate::prelude::{ColliderEnabled, IntegrationParameters};
|
||||||
use na::Unit;
|
use na::Unit;
|
||||||
use parry::bounding_volume::{Aabb, BoundingVolume};
|
use parry::bounding_volume::{Aabb, BoundingVolume};
|
||||||
use parry::shape::{Shape, TriMeshBuilderError, TriMeshFlags};
|
use parry::shape::{Shape, TriMeshBuilderError, TriMeshFlags};
|
||||||
@@ -457,6 +457,40 @@ impl Collider {
|
|||||||
self.shape.compute_swept_aabb(&self.pos, next_position)
|
self.shape.compute_swept_aabb(&self.pos, next_position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: we have a lot of different AABB computation functions
|
||||||
|
// We should group them somehow.
|
||||||
|
/// Computes the collider’s AABB for usage in a broad-phase.
|
||||||
|
///
|
||||||
|
/// It takes into account soft-ccd, the contact skin, and the contact prediction.
|
||||||
|
pub fn compute_broad_phase_aabb(
|
||||||
|
&self,
|
||||||
|
params: &IntegrationParameters,
|
||||||
|
bodies: &RigidBodySet,
|
||||||
|
) -> Aabb {
|
||||||
|
// Take soft-ccd into account by growing the aabb.
|
||||||
|
let next_pose = self.parent.and_then(|p| {
|
||||||
|
let parent = bodies.get(p.handle)?;
|
||||||
|
(parent.soft_ccd_prediction() > 0.0).then(|| {
|
||||||
|
parent.predict_position_using_velocity_and_forces_with_max_dist(
|
||||||
|
params.dt,
|
||||||
|
parent.soft_ccd_prediction(),
|
||||||
|
) * p.pos_wrt_parent
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let prediction_distance = params.prediction_distance();
|
||||||
|
let mut aabb = self.compute_collision_aabb(prediction_distance / 2.0);
|
||||||
|
if let Some(next_pose) = next_pose {
|
||||||
|
let next_aabb = self
|
||||||
|
.shape
|
||||||
|
.compute_aabb(&next_pose)
|
||||||
|
.loosened(self.contact_skin() + prediction_distance / 2.0);
|
||||||
|
aabb.merge(&next_aabb);
|
||||||
|
}
|
||||||
|
|
||||||
|
aabb
|
||||||
|
}
|
||||||
|
|
||||||
/// Compute the local-space mass properties of this collider.
|
/// Compute the local-space mass properties of this collider.
|
||||||
pub fn mass_properties(&self) -> MassProperties {
|
pub fn mass_properties(&self) -> MassProperties {
|
||||||
self.mprops.mass_properties(&*self.shape)
|
self.mprops.mass_properties(&*self.shape)
|
||||||
|
|||||||
@@ -53,6 +53,10 @@ impl ColliderSet {
|
|||||||
std::mem::take(&mut self.modified_colliders)
|
std::mem::take(&mut self.modified_colliders)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_modified(&mut self, modified: ModifiedColliders) {
|
||||||
|
self.modified_colliders = modified;
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn take_removed(&mut self) -> Vec<ColliderHandle> {
|
pub(crate) fn take_removed(&mut self) -> Vec<ColliderHandle> {
|
||||||
std::mem::take(&mut self.removed_colliders)
|
std::mem::take(&mut self.removed_colliders)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
//! Structures related to geometry: colliders, shapes, etc.
|
//! Structures related to geometry: colliders, shapes, etc.
|
||||||
|
|
||||||
pub use self::broad_phase::BroadPhase;
|
|
||||||
pub use self::broad_phase_bvh::{BroadPhaseBvh, BvhOptimizationStrategy};
|
pub use self::broad_phase_bvh::{BroadPhaseBvh, BvhOptimizationStrategy};
|
||||||
pub use self::broad_phase_pair_event::{BroadPhasePairEvent, ColliderPair};
|
pub use self::broad_phase_pair_event::{BroadPhasePairEvent, ColliderPair};
|
||||||
pub use self::collider::{Collider, ColliderBuilder};
|
pub use self::collider::{Collider, ColliderBuilder};
|
||||||
@@ -199,7 +198,6 @@ mod interaction_graph;
|
|||||||
mod interaction_groups;
|
mod interaction_groups;
|
||||||
mod narrow_phase;
|
mod narrow_phase;
|
||||||
|
|
||||||
mod broad_phase;
|
|
||||||
mod broad_phase_bvh;
|
mod broad_phase_bvh;
|
||||||
mod broad_phase_pair_event;
|
mod broad_phase_pair_event;
|
||||||
mod collider;
|
mod collider;
|
||||||
|
|||||||
@@ -697,14 +697,9 @@ impl NarrowPhase {
|
|||||||
&mut self,
|
&mut self,
|
||||||
bodies: &RigidBodySet,
|
bodies: &RigidBodySet,
|
||||||
colliders: &ColliderSet,
|
colliders: &ColliderSet,
|
||||||
modified_colliders: &[ColliderHandle],
|
|
||||||
hooks: &dyn PhysicsHooks,
|
hooks: &dyn PhysicsHooks,
|
||||||
events: &dyn EventHandler,
|
events: &dyn EventHandler,
|
||||||
) {
|
) {
|
||||||
if modified_colliders.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let nodes = &self.intersection_graph.graph.nodes;
|
let nodes = &self.intersection_graph.graph.nodes;
|
||||||
let query_dispatcher = &*self.query_dispatcher;
|
let query_dispatcher = &*self.query_dispatcher;
|
||||||
|
|
||||||
@@ -806,14 +801,9 @@ impl NarrowPhase {
|
|||||||
colliders: &ColliderSet,
|
colliders: &ColliderSet,
|
||||||
impulse_joints: &ImpulseJointSet,
|
impulse_joints: &ImpulseJointSet,
|
||||||
multibody_joints: &MultibodyJointSet,
|
multibody_joints: &MultibodyJointSet,
|
||||||
modified_colliders: &[ColliderHandle],
|
|
||||||
hooks: &dyn PhysicsHooks,
|
hooks: &dyn PhysicsHooks,
|
||||||
events: &dyn EventHandler,
|
events: &dyn EventHandler,
|
||||||
) {
|
) {
|
||||||
if modified_colliders.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let query_dispatcher = &*self.query_dispatcher;
|
let query_dispatcher = &*self.query_dispatcher;
|
||||||
|
|
||||||
// TODO: don't iterate on all the edges.
|
// TODO: don't iterate on all the edges.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::dynamics::{ImpulseJointSet, IntegrationParameters, MultibodyJointSet};
|
use crate::dynamics::{ImpulseJointSet, IntegrationParameters, MultibodyJointSet};
|
||||||
use crate::geometry::{
|
use crate::geometry::{
|
||||||
BroadPhase, BroadPhasePairEvent, ColliderChanges, ColliderHandle, ColliderPair,
|
BroadPhaseBvh, BroadPhasePairEvent, ColliderChanges, ColliderHandle, ColliderPair,
|
||||||
ModifiedColliders, NarrowPhase,
|
ModifiedColliders, NarrowPhase,
|
||||||
};
|
};
|
||||||
use crate::math::Real;
|
use crate::math::Real;
|
||||||
@@ -44,7 +44,7 @@ impl CollisionPipeline {
|
|||||||
fn detect_collisions(
|
fn detect_collisions(
|
||||||
&mut self,
|
&mut self,
|
||||||
prediction_distance: Real,
|
prediction_distance: Real,
|
||||||
broad_phase: &mut dyn BroadPhase,
|
broad_phase: &mut BroadPhaseBvh,
|
||||||
narrow_phase: &mut NarrowPhase,
|
narrow_phase: &mut NarrowPhase,
|
||||||
bodies: &mut RigidBodySet,
|
bodies: &mut RigidBodySet,
|
||||||
colliders: &mut ColliderSet,
|
colliders: &mut ColliderSet,
|
||||||
@@ -93,11 +93,10 @@ impl CollisionPipeline {
|
|||||||
colliders,
|
colliders,
|
||||||
&ImpulseJointSet::new(),
|
&ImpulseJointSet::new(),
|
||||||
&MultibodyJointSet::new(),
|
&MultibodyJointSet::new(),
|
||||||
modified_colliders,
|
|
||||||
hooks,
|
hooks,
|
||||||
events,
|
events,
|
||||||
);
|
);
|
||||||
narrow_phase.compute_intersections(bodies, colliders, modified_colliders, hooks, events);
|
narrow_phase.compute_intersections(bodies, colliders, hooks, events);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_modified_colliders(
|
fn clear_modified_colliders(
|
||||||
@@ -118,7 +117,7 @@ impl CollisionPipeline {
|
|||||||
pub fn step(
|
pub fn step(
|
||||||
&mut self,
|
&mut self,
|
||||||
prediction_distance: Real,
|
prediction_distance: Real,
|
||||||
broad_phase: &mut dyn BroadPhase,
|
broad_phase: &mut BroadPhaseBvh,
|
||||||
narrow_phase: &mut NarrowPhase,
|
narrow_phase: &mut NarrowPhase,
|
||||||
bodies: &mut RigidBodySet,
|
bodies: &mut RigidBodySet,
|
||||||
colliders: &mut ColliderSet,
|
colliders: &mut ColliderSet,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use crate::dynamics::{
|
|||||||
RigidBodyChanges, RigidBodyPosition, RigidBodyType,
|
RigidBodyChanges, RigidBodyPosition, RigidBodyType,
|
||||||
};
|
};
|
||||||
use crate::geometry::{
|
use crate::geometry::{
|
||||||
BroadPhase, BroadPhasePairEvent, ColliderChanges, ColliderHandle, ColliderPair,
|
BroadPhaseBvh, BroadPhasePairEvent, ColliderChanges, ColliderHandle, ColliderPair,
|
||||||
ContactManifoldIndex, ModifiedColliders, NarrowPhase, TemporaryInteractionIndex,
|
ContactManifoldIndex, ModifiedColliders, NarrowPhase, TemporaryInteractionIndex,
|
||||||
};
|
};
|
||||||
use crate::math::{Real, Vector};
|
use crate::math::{Real, Vector};
|
||||||
@@ -71,11 +71,14 @@ impl PhysicsPipeline {
|
|||||||
colliders: &mut ColliderSet,
|
colliders: &mut ColliderSet,
|
||||||
modified_colliders: &mut ModifiedColliders,
|
modified_colliders: &mut ModifiedColliders,
|
||||||
) {
|
) {
|
||||||
for handle in modified_colliders.iter() {
|
for co in colliders.colliders.iter_mut() {
|
||||||
if let Some(co) = colliders.get_mut_internal(*handle) {
|
co.1.changes = ColliderChanges::empty();
|
||||||
co.changes = ColliderChanges::empty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// for handle in modified_colliders.iter() {
|
||||||
|
// if let Some(co) = colliders.get_mut_internal(*handle) {
|
||||||
|
// co.changes = ColliderChanges::empty();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
modified_colliders.clear();
|
modified_colliders.clear();
|
||||||
}
|
}
|
||||||
@@ -98,7 +101,7 @@ impl PhysicsPipeline {
|
|||||||
&mut self,
|
&mut self,
|
||||||
integration_parameters: &IntegrationParameters,
|
integration_parameters: &IntegrationParameters,
|
||||||
islands: &mut IslandManager,
|
islands: &mut IslandManager,
|
||||||
broad_phase: &mut dyn BroadPhase,
|
broad_phase: &mut BroadPhaseBvh,
|
||||||
narrow_phase: &mut NarrowPhase,
|
narrow_phase: &mut NarrowPhase,
|
||||||
bodies: &mut RigidBodySet,
|
bodies: &mut RigidBodySet,
|
||||||
colliders: &mut ColliderSet,
|
colliders: &mut ColliderSet,
|
||||||
@@ -153,11 +156,10 @@ impl PhysicsPipeline {
|
|||||||
colliders,
|
colliders,
|
||||||
impulse_joints,
|
impulse_joints,
|
||||||
multibody_joints,
|
multibody_joints,
|
||||||
modified_colliders,
|
|
||||||
hooks,
|
hooks,
|
||||||
events,
|
events,
|
||||||
);
|
);
|
||||||
narrow_phase.compute_intersections(bodies, colliders, modified_colliders, hooks, events);
|
narrow_phase.compute_intersections(bodies, colliders, hooks, events);
|
||||||
|
|
||||||
self.counters.cd.narrow_phase_time.pause();
|
self.counters.cd.narrow_phase_time.pause();
|
||||||
self.counters.stages.collision_detection_time.pause();
|
self.counters.stages.collision_detection_time.pause();
|
||||||
@@ -340,6 +342,7 @@ impl PhysicsPipeline {
|
|||||||
islands: &IslandManager,
|
islands: &IslandManager,
|
||||||
bodies: &mut RigidBodySet,
|
bodies: &mut RigidBodySet,
|
||||||
colliders: &mut ColliderSet,
|
colliders: &mut ColliderSet,
|
||||||
|
broad_phase: &mut BroadPhaseBvh,
|
||||||
narrow_phase: &NarrowPhase,
|
narrow_phase: &NarrowPhase,
|
||||||
ccd_solver: &mut CCDSolver,
|
ccd_solver: &mut CCDSolver,
|
||||||
events: &dyn EventHandler,
|
events: &dyn EventHandler,
|
||||||
@@ -347,10 +350,11 @@ impl PhysicsPipeline {
|
|||||||
self.counters.ccd.toi_computation_time.start();
|
self.counters.ccd.toi_computation_time.start();
|
||||||
// Handle CCD
|
// Handle CCD
|
||||||
let impacts = ccd_solver.predict_impacts_at_next_positions(
|
let impacts = ccd_solver.predict_impacts_at_next_positions(
|
||||||
integration_parameters.dt,
|
integration_parameters,
|
||||||
islands,
|
islands,
|
||||||
bodies,
|
bodies,
|
||||||
colliders,
|
colliders,
|
||||||
|
broad_phase,
|
||||||
narrow_phase,
|
narrow_phase,
|
||||||
events,
|
events,
|
||||||
);
|
);
|
||||||
@@ -414,7 +418,7 @@ impl PhysicsPipeline {
|
|||||||
gravity: &Vector<Real>,
|
gravity: &Vector<Real>,
|
||||||
integration_parameters: &IntegrationParameters,
|
integration_parameters: &IntegrationParameters,
|
||||||
islands: &mut IslandManager,
|
islands: &mut IslandManager,
|
||||||
broad_phase: &mut dyn BroadPhase,
|
broad_phase: &mut BroadPhaseBvh,
|
||||||
narrow_phase: &mut NarrowPhase,
|
narrow_phase: &mut NarrowPhase,
|
||||||
bodies: &mut RigidBodySet,
|
bodies: &mut RigidBodySet,
|
||||||
colliders: &mut ColliderSet,
|
colliders: &mut ColliderSet,
|
||||||
@@ -535,9 +539,11 @@ impl PhysicsPipeline {
|
|||||||
let first_impact = if ccd_active {
|
let first_impact = if ccd_active {
|
||||||
ccd_solver.find_first_impact(
|
ccd_solver.find_first_impact(
|
||||||
remaining_time,
|
remaining_time,
|
||||||
|
&integration_parameters,
|
||||||
islands,
|
islands,
|
||||||
bodies,
|
bodies,
|
||||||
colliders,
|
colliders,
|
||||||
|
broad_phase,
|
||||||
narrow_phase,
|
narrow_phase,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@@ -605,6 +611,7 @@ impl PhysicsPipeline {
|
|||||||
islands,
|
islands,
|
||||||
bodies,
|
bodies,
|
||||||
colliders,
|
colliders,
|
||||||
|
broad_phase,
|
||||||
narrow_phase,
|
narrow_phase,
|
||||||
ccd_solver,
|
ccd_solver,
|
||||||
events,
|
events,
|
||||||
@@ -616,23 +623,35 @@ impl PhysicsPipeline {
|
|||||||
self.advance_to_final_positions(islands, bodies, colliders, &mut modified_colliders);
|
self.advance_to_final_positions(islands, bodies, colliders, &mut modified_colliders);
|
||||||
self.counters.stages.update_time.pause();
|
self.counters.stages.update_time.pause();
|
||||||
|
|
||||||
self.detect_collisions(
|
if remaining_substeps > 0 {
|
||||||
&integration_parameters,
|
self.detect_collisions(
|
||||||
islands,
|
&integration_parameters,
|
||||||
broad_phase,
|
islands,
|
||||||
narrow_phase,
|
broad_phase,
|
||||||
bodies,
|
narrow_phase,
|
||||||
colliders,
|
bodies,
|
||||||
impulse_joints,
|
colliders,
|
||||||
multibody_joints,
|
impulse_joints,
|
||||||
&modified_colliders,
|
multibody_joints,
|
||||||
&[],
|
&modified_colliders,
|
||||||
hooks,
|
&[],
|
||||||
events,
|
hooks,
|
||||||
false,
|
events,
|
||||||
);
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
self.clear_modified_colliders(colliders, &mut modified_colliders);
|
self.clear_modified_colliders(colliders, &mut modified_colliders);
|
||||||
|
} else {
|
||||||
|
// If we ran the last substep, just update the broad-phase bvh instead
|
||||||
|
// of a full collision-detection step.
|
||||||
|
for handle in modified_colliders.iter() {
|
||||||
|
let co = &colliders[*handle];
|
||||||
|
let aabb = co.compute_broad_phase_aabb(&integration_parameters, bodies);
|
||||||
|
broad_phase.set_aabb(&integration_parameters, *handle, aabb);
|
||||||
|
}
|
||||||
|
modified_colliders.clear();
|
||||||
|
// self.clear_modified_colliders(colliders, &mut modified_colliders);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, make sure we update the world mass-properties of the rigid-bodies
|
// Finally, make sure we update the world mass-properties of the rigid-bodies
|
||||||
@@ -648,6 +667,9 @@ impl PhysicsPipeline {
|
|||||||
}
|
}
|
||||||
self.counters.stages.update_time.pause();
|
self.counters.stages.update_time.pause();
|
||||||
|
|
||||||
|
// Re-insert the modified vector we extracted for the borrow-checker.
|
||||||
|
colliders.set_modified(modified_colliders);
|
||||||
|
|
||||||
self.counters.step_completed();
|
self.counters.step_completed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ use rapier::math::{Isometry, Real, Vector};
|
|||||||
//use crate::objects::polyline::Polyline;
|
//use crate::objects::polyline::Polyline;
|
||||||
// use crate::objects::mesh::Mesh;
|
// use crate::objects::mesh::Mesh;
|
||||||
use crate::testbed::TestbedStateFlags;
|
use crate::testbed::TestbedStateFlags;
|
||||||
use rand::{Rng, SeedableRng};
|
|
||||||
use rand_pcg::Pcg32;
|
use rand_pcg::Pcg32;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@@ -97,7 +96,7 @@ pub struct GraphicsManager {
|
|||||||
impl GraphicsManager {
|
impl GraphicsManager {
|
||||||
pub fn new() -> GraphicsManager {
|
pub fn new() -> GraphicsManager {
|
||||||
GraphicsManager {
|
GraphicsManager {
|
||||||
rand: Pcg32::seed_from_u64(0),
|
rand: Pcg32::new(0, 1),
|
||||||
b2sn: HashMap::new(),
|
b2sn: HashMap::new(),
|
||||||
b2color: HashMap::new(),
|
b2color: HashMap::new(),
|
||||||
c2color: HashMap::new(),
|
c2color: HashMap::new(),
|
||||||
@@ -128,7 +127,7 @@ impl GraphicsManager {
|
|||||||
self.c2color.clear();
|
self.c2color.clear();
|
||||||
self.b2color.clear();
|
self.b2color.clear();
|
||||||
self.b2wireframe.clear();
|
self.b2wireframe.clear();
|
||||||
self.rand = Pcg32::seed_from_u64(0);
|
self.rand = Pcg32::new(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_collider_nodes(
|
pub fn remove_collider_nodes(
|
||||||
@@ -236,7 +235,8 @@ impl GraphicsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn gen_color(rng: &mut Pcg32) -> Point3<f32> {
|
fn gen_color(rng: &mut Pcg32) -> Point3<f32> {
|
||||||
let mut color: Point3<f32> = rng.r#gen();
|
use rand::Rng;
|
||||||
|
let mut color: Point3<f32> = rng.random();
|
||||||
|
|
||||||
// Quantize the colors a bit to get some amount of auto-instancing from bevy.
|
// Quantize the colors a bit to get some amount of auto-instancing from bevy.
|
||||||
color.x = (color.x * 5.0).round() / 5.0;
|
color.x = (color.x * 5.0).round() / 5.0;
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ use rapier::dynamics::{
|
|||||||
CCDSolver, ImpulseJointSet, IntegrationParameters, IslandManager, MultibodyJointSet,
|
CCDSolver, ImpulseJointSet, IntegrationParameters, IslandManager, MultibodyJointSet,
|
||||||
RigidBodySet,
|
RigidBodySet,
|
||||||
};
|
};
|
||||||
use rapier::geometry::{
|
use rapier::geometry::{BroadPhaseBvh, BvhOptimizationStrategy, ColliderSet, NarrowPhase};
|
||||||
BroadPhase, BroadPhaseBvh, BvhOptimizationStrategy, ColliderSet, NarrowPhase,
|
|
||||||
};
|
|
||||||
use rapier::math::{Real, Vector};
|
use rapier::math::{Real, Vector};
|
||||||
use rapier::pipeline::{ChannelEventCollector, PhysicsHooks, PhysicsPipeline};
|
use rapier::pipeline::{ChannelEventCollector, PhysicsHooks, PhysicsPipeline};
|
||||||
|
|
||||||
@@ -25,16 +23,14 @@ pub enum RapierBroadPhaseType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RapierBroadPhaseType {
|
impl RapierBroadPhaseType {
|
||||||
pub fn init_broad_phase(self) -> Box<dyn BroadPhase> {
|
pub fn init_broad_phase(self) -> BroadPhaseBvh {
|
||||||
match self {
|
match self {
|
||||||
RapierBroadPhaseType::BvhSubtreeOptimizer => {
|
RapierBroadPhaseType::BvhSubtreeOptimizer => {
|
||||||
Box::new(BroadPhaseBvh::with_optimization_strategy(
|
BroadPhaseBvh::with_optimization_strategy(BvhOptimizationStrategy::SubtreeOptimizer)
|
||||||
BvhOptimizationStrategy::SubtreeOptimizer,
|
}
|
||||||
))
|
RapierBroadPhaseType::BvhWithoutOptimization => {
|
||||||
|
BroadPhaseBvh::with_optimization_strategy(BvhOptimizationStrategy::None)
|
||||||
}
|
}
|
||||||
RapierBroadPhaseType::BvhWithoutOptimization => Box::new(
|
|
||||||
BroadPhaseBvh::with_optimization_strategy(BvhOptimizationStrategy::None),
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -250,7 +246,7 @@ impl Harness {
|
|||||||
&physics.gravity,
|
&physics.gravity,
|
||||||
&physics.integration_parameters,
|
&physics.integration_parameters,
|
||||||
&mut physics.islands,
|
&mut physics.islands,
|
||||||
&mut *physics.broad_phase,
|
&mut physics.broad_phase,
|
||||||
&mut physics.narrow_phase,
|
&mut physics.narrow_phase,
|
||||||
&mut physics.bodies,
|
&mut physics.bodies,
|
||||||
&mut physics.colliders,
|
&mut physics.colliders,
|
||||||
@@ -268,7 +264,7 @@ impl Harness {
|
|||||||
&self.physics.gravity,
|
&self.physics.gravity,
|
||||||
&self.physics.integration_parameters,
|
&self.physics.integration_parameters,
|
||||||
&mut self.physics.islands,
|
&mut self.physics.islands,
|
||||||
&mut *self.physics.broad_phase,
|
&mut self.physics.broad_phase,
|
||||||
&mut self.physics.narrow_phase,
|
&mut self.physics.narrow_phase,
|
||||||
&mut self.physics.bodies,
|
&mut self.physics.bodies,
|
||||||
&mut self.physics.colliders,
|
&mut self.physics.colliders,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use rapier::dynamics::{
|
|||||||
RigidBodySet,
|
RigidBodySet,
|
||||||
};
|
};
|
||||||
use rapier::geometry::{
|
use rapier::geometry::{
|
||||||
BroadPhase, ColliderSet, CollisionEvent, ContactForceEvent, DefaultBroadPhase, NarrowPhase,
|
BroadPhaseBvh, ColliderSet, CollisionEvent, ContactForceEvent, DefaultBroadPhase, NarrowPhase,
|
||||||
};
|
};
|
||||||
use rapier::math::{Real, Vector};
|
use rapier::math::{Real, Vector};
|
||||||
use rapier::pipeline::{PhysicsHooks, PhysicsPipeline};
|
use rapier::pipeline::{PhysicsHooks, PhysicsPipeline};
|
||||||
@@ -89,7 +89,7 @@ impl PhysicsSnapshot {
|
|||||||
|
|
||||||
pub struct PhysicsState {
|
pub struct PhysicsState {
|
||||||
pub islands: IslandManager,
|
pub islands: IslandManager,
|
||||||
pub broad_phase: Box<dyn BroadPhase>,
|
pub broad_phase: BroadPhaseBvh,
|
||||||
pub narrow_phase: NarrowPhase,
|
pub narrow_phase: NarrowPhase,
|
||||||
pub bodies: RigidBodySet,
|
pub bodies: RigidBodySet,
|
||||||
pub colliders: ColliderSet,
|
pub colliders: ColliderSet,
|
||||||
@@ -112,7 +112,7 @@ impl PhysicsState {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
islands: IslandManager::new(),
|
islands: IslandManager::new(),
|
||||||
broad_phase: Box::new(DefaultBroadPhase::default()),
|
broad_phase: DefaultBroadPhase::default(),
|
||||||
narrow_phase: NarrowPhase::new(),
|
narrow_phase: NarrowPhase::new(),
|
||||||
bodies: RigidBodySet::new(),
|
bodies: RigidBodySet::new(),
|
||||||
colliders: ColliderSet::new(),
|
colliders: ColliderSet::new(),
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use rapier::dynamics::{
|
|||||||
RigidBodyHandle, RigidBodySet,
|
RigidBodyHandle, RigidBodySet,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
use rapier::geometry::{BroadPhaseBvh, Ray};
|
use rapier::geometry::Ray;
|
||||||
use rapier::geometry::{ColliderHandle, ColliderSet, NarrowPhase};
|
use rapier::geometry::{ColliderHandle, ColliderSet, NarrowPhase};
|
||||||
use rapier::math::{Real, Vector};
|
use rapier::math::{Real, Vector};
|
||||||
use rapier::pipeline::PhysicsHooks;
|
use rapier::pipeline::PhysicsHooks;
|
||||||
@@ -814,21 +814,12 @@ impl Testbed<'_, '_, '_, '_, '_, '_, '_, '_, '_, '_, '_, '_, '_> {
|
|||||||
wheels[1].engine_force = engine_force;
|
wheels[1].engine_force = engine_force;
|
||||||
wheels[1].steering = steering_angle;
|
wheels[1].steering = steering_angle;
|
||||||
|
|
||||||
let query_pipeline = if let Some(bf) = self
|
let query_pipeline = self.harness.physics.broad_phase.as_query_pipeline_mut(
|
||||||
.harness
|
self.harness.physics.narrow_phase.query_dispatcher(),
|
||||||
.physics
|
&mut self.harness.physics.bodies,
|
||||||
.broad_phase
|
&mut self.harness.physics.colliders,
|
||||||
.downcast_ref::<BroadPhaseBvh>()
|
QueryFilter::exclude_dynamic().exclude_rigid_body(vehicle.chassis),
|
||||||
{
|
);
|
||||||
bf.as_query_pipeline_mut(
|
|
||||||
self.harness.physics.narrow_phase.query_dispatcher(),
|
|
||||||
&mut self.harness.physics.bodies,
|
|
||||||
&mut self.harness.physics.colliders,
|
|
||||||
QueryFilter::exclude_dynamic().exclude_rigid_body(vehicle.chassis),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
vehicle.update_vehicle(
|
vehicle.update_vehicle(
|
||||||
self.harness.physics.integration_parameters.dt,
|
self.harness.physics.integration_parameters.dt,
|
||||||
@@ -1353,7 +1344,7 @@ fn update_testbed(
|
|||||||
}
|
}
|
||||||
|
|
||||||
harness.state.timestep_id = timestep_id;
|
harness.state.timestep_id = timestep_id;
|
||||||
harness.physics.broad_phase = Box::new(broad_phase);
|
harness.physics.broad_phase = broad_phase;
|
||||||
harness.physics.narrow_phase = narrow_phase;
|
harness.physics.narrow_phase = narrow_phase;
|
||||||
harness.physics.islands = island_manager;
|
harness.physics.islands = island_manager;
|
||||||
harness.physics.bodies = bodies;
|
harness.physics.bodies = bodies;
|
||||||
@@ -1630,16 +1621,12 @@ fn highlight_hovered_body(
|
|||||||
let ray_dir = Vector3::new(ray_dir.x as Real, ray_dir.y as Real, ray_dir.z as Real);
|
let ray_dir = Vector3::new(ray_dir.x as Real, ray_dir.y as Real, ray_dir.z as Real);
|
||||||
|
|
||||||
let ray = Ray::new(ray_origin, ray_dir);
|
let ray = Ray::new(ray_origin, ray_dir);
|
||||||
let query_pipeline = if let Some(bf) = physics.broad_phase.downcast_ref::<BroadPhaseBvh>() {
|
let query_pipeline = physics.broad_phase.as_query_pipeline(
|
||||||
bf.as_query_pipeline(
|
physics.narrow_phase.query_dispatcher(),
|
||||||
physics.narrow_phase.query_dispatcher(),
|
&physics.bodies,
|
||||||
&physics.bodies,
|
&physics.colliders,
|
||||||
&physics.colliders,
|
QueryFilter::only_dynamic(),
|
||||||
QueryFilter::only_dynamic(),
|
);
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let hit = query_pipeline.cast_ray(&ray, Real::MAX, true);
|
let hit = query_pipeline.cast_ray(&ray, Real::MAX, true);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user