Skip to content
This repository has been archived by the owner on Aug 1, 2022. It is now read-only.

Commit

Permalink
Remove AsyncCollider and AsyncSceneCollider
Browse files Browse the repository at this point in the history
This will be solved on the Bevy side with asset preprocessing: bevyengine/bevy#4933. In the meanwhile there is a dedicated plugin that can do this and even more: https://github.com/nicopap/bevy-scene-hook.
  • Loading branch information
Shatur committed Jul 28, 2022
1 parent 8378615 commit d159770
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 243 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Unreleased
### Removed
- `AsyncCollider` and `AsyncSceneCollider`. The approach used is very restrictive. This will be solved on the Bevy side with asset preprocessing: https://github.com/bevyengine/bevy/issues/4933. In the meanwhile there is a dedicated plugin that can do this and even more: https://github.com/nicopap/bevy-scene-hook.

## 0.15.0 (10 July 2022)
### Fixed
- Fix unpredictable broad-phase panic when using small colliders in the simulation.
Expand Down
38 changes: 0 additions & 38 deletions src/geometry/collider.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
#[cfg(feature = "dim3")]
use crate::geometry::VHACDParameters;
use bevy::prelude::*;
use bevy::reflect::FromReflect;
#[cfg(feature = "dim3")]
use bevy::utils::HashMap;
use bevy::utils::HashSet;
use rapier::prelude::{ColliderHandle, InteractionGroups, SharedShape};

Expand All @@ -14,40 +10,6 @@ use crate::math::Vect;
#[derive(Copy, Clone, Debug, Component)]
pub struct RapierColliderHandle(pub ColliderHandle);

/// A component which will be replaced by the specified collider type after the referenced mesh become available.
#[cfg(feature = "dim3")]
#[derive(Component, Debug, Clone)]
pub struct AsyncCollider {
/// Mesh handle to use for collider generation.
pub handle: Handle<Mesh>,
/// Collider type that will be generated.
pub shape: ComputedColliderShape,
}

/// A component which will be replaced the specified collider types on children with meshes after the referenced scene become available.
#[cfg(feature = "dim3")]
#[derive(Component, Debug, Clone)]
pub struct AsyncSceneCollider {
/// Scene handle to use for colliders generation.
pub handle: Handle<Scene>,
/// Collider type for each scene mesh not included in [`named_shapes`]. If [`None`], then all
/// shapes will be skipped for processing except [`named_shapes`].
pub shape: Option<ComputedColliderShape>,
/// Shape types for meshes by name. If shape is [`None`], then it will be skipped for
/// processing.
pub named_shapes: HashMap<String, Option<ComputedColliderShape>>,
}

/// Shape type based on a Bevy mesh asset.
#[cfg(feature = "dim3")]
#[derive(Debug, Clone)]
pub enum ComputedColliderShape {
/// Triangle-mesh.
TriMesh,
/// Convex decomposition.
ConvexDecomposition(VHACDParameters),
}

/// A geometric entity that can be attached to a body so it can be affected by contacts
/// and intersection queries.
#[derive(Component, Clone)] // TODO: Reflect
Expand Down
38 changes: 24 additions & 14 deletions src/geometry/collider_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ use {
use rapier::prelude::{FeatureId, Point, Ray, SharedShape, Vector, DIM};

use super::shape_views::*;
#[cfg(feature = "dim3")]
use crate::geometry::ComputedColliderShape;
use crate::geometry::{Collider, PointProjection, RayIntersection, VHACDParameters};
use crate::math::{Real, Rot, Vect};

Expand Down Expand Up @@ -160,18 +158,30 @@ impl Collider {
///
/// Returns `None` if the index buffer or vertex buffer of the mesh are in an incompatible format.
#[cfg(feature = "dim3")]
pub fn from_bevy_mesh(mesh: &Mesh, collider_shape: &ComputedColliderShape) -> Option<Self> {
let vertices_indices = extract_mesh_vertices_indices(mesh);
match collider_shape {
ComputedColliderShape::TriMesh => {
vertices_indices.map(|(vtx, idx)| SharedShape::trimesh(vtx, idx).into())
}
ComputedColliderShape::ConvexDecomposition(params) => {
vertices_indices.map(|(vtx, idx)| {
SharedShape::convex_decomposition_with_params(&vtx, &idx, params).into()
})
}
}
pub fn bevy_mesh(mesh: &Mesh) -> Option<Self> {
extract_mesh_vertices_indices(mesh).map(|(vtx, idx)| SharedShape::trimesh(vtx, idx).into())
}

/// Initializes a collider with the convex decomposition of a Bevy Mesh.
///
/// Returns `None` if the index buffer or vertex buffer of the mesh are in an incompatible format.
#[cfg(feature = "dim3")]
pub fn bevy_mesh_convex_decomposition(mesh: &Mesh) -> Option<Self> {
extract_mesh_vertices_indices(mesh)
.map(|(vtx, idx)| SharedShape::convex_decomposition(&vtx, &idx).into())
}

/// Initializes a collider with the convex decomposition of a Bevy Mesh, using custom convex decomposition parameters.
///
/// Returns `None` if the index buffer or vertex buffer of the mesh are in an incompatible format.
#[cfg(feature = "dim3")]
pub fn bevy_mesh_convex_decomposition_with_params(
mesh: &Mesh,
params: &VHACDParameters,
) -> Option<Self> {
extract_mesh_vertices_indices(mesh).map(|(vtx, idx)| {
SharedShape::convex_decomposition_with_params(&vtx, &idx, params).into()
})
}

/// Initializes a collider with a compound shape obtained from the decomposition of
Expand Down
23 changes: 3 additions & 20 deletions src/plugin/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,11 @@ impl<PhysicsHooksData: 'static + WorldQuery + Send + Sync> RapierPhysicsPlugin<P
pub fn get_systems(stage: PhysicsStages) -> SystemSet {
match stage {
PhysicsStages::SyncBackend => {
let systems = SystemSet::new()
SystemSet::new()
.with_system(bevy::transform::transform_propagate_system) // Run Bevy transform propagation additionaly to sync [`GlobalTransform`]
.with_system(
systems::init_async_colliders
.after(bevy::transform::transform_propagate_system),
systems::apply_scale.after(bevy::transform::transform_propagate_system),
)
.with_system(systems::apply_scale.after(systems::init_async_colliders))
.with_system(systems::apply_collider_user_changes.after(systems::apply_scale))
.with_system(
systems::apply_rigid_body_user_changes
Expand All @@ -77,11 +75,7 @@ impl<PhysicsHooksData: 'static + WorldQuery + Send + Sync> RapierPhysicsPlugin<P
.with_system(
systems::init_rigid_bodies.after(systems::apply_joint_user_changes),
)
.with_system(
systems::init_colliders
.after(systems::init_rigid_bodies)
.after(systems::init_async_colliders),
)
.with_system(systems::init_colliders.after(systems::init_rigid_bodies))
.with_system(systems::init_joints.after(systems::init_colliders))
.with_system(
systems::apply_initial_rigid_body_impulses.after(systems::init_colliders),
Expand All @@ -90,18 +84,7 @@ impl<PhysicsHooksData: 'static + WorldQuery + Send + Sync> RapierPhysicsPlugin<P
systems::sync_removals
.after(systems::init_joints)
.after(systems::apply_initial_rigid_body_impulses),
);

#[cfg(feature = "dim3")]
{
systems.with_system(
systems::init_async_scene_colliders.before(systems::init_async_colliders),
)
}
#[cfg(not(feature = "dim3"))]
{
systems
}
}
PhysicsStages::StepSimulation => {
SystemSet::new().with_system(systems::step_simulation::<PhysicsHooksData>)
Expand Down
171 changes: 0 additions & 171 deletions src/plugin/systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ use bevy::prelude::*;
use rapier::prelude::*;
use std::collections::HashMap;

#[cfg(feature = "dim3")]
use crate::prelude::{AsyncCollider, AsyncSceneCollider};

/// Components that will be updated after a physics step.
pub type RigidBodyWritebackComponents<'a> = (
Entity,
Expand Down Expand Up @@ -598,83 +595,6 @@ pub fn step_simulation<PhysicsHooksData: 'static + WorldQuery + Send + Sync>(
}
}

/// NOTE: This currently does nothing in 2D.
#[cfg(feature = "dim2")]
pub fn init_async_colliders() {}

/// System responsible for creating `Collider` components from `AsyncCollider` components if the
/// corresponding mesh has become available.
#[cfg(feature = "dim3")]
pub fn init_async_colliders(
mut commands: Commands,
meshes: Res<Assets<Mesh>>,
async_colliders: Query<(Entity, &AsyncCollider)>,
) {
for (entity, async_collider) in async_colliders.iter() {
if let Some(mesh) = meshes.get(&async_collider.handle) {
match Collider::from_bevy_mesh(mesh, &async_collider.shape) {
Some(collider) => {
commands
.entity(entity)
.insert(collider)
.remove::<AsyncCollider>();
}
None => error!("Unable to generate collider from mesh {:?}", mesh),
}
}
}
}

/// System responsible for creating `Collider` components from `AsyncSceneCollider` components if the
/// corresponding scene has become available.
#[cfg(feature = "dim3")]
pub fn init_async_scene_colliders(
mut commands: Commands,
meshes: Res<Assets<Mesh>>,
scenes: Res<Assets<Scene>>,
async_colliders: Query<(Entity, &AsyncSceneCollider)>,
children: Query<&Children>,
mesh_handles: Query<(&Name, &Handle<Mesh>)>,
) {
for (entity, async_collider) in async_colliders.iter() {
if scenes.get(&async_collider.handle).is_some() {
traverse_descendants(entity, &children, &mut |child| {
if let Ok((name, handle)) = mesh_handles.get(child) {
let shape = async_collider
.named_shapes
.get(name.as_str())
.unwrap_or(&async_collider.shape);
if let Some(shape) = shape {
let mesh = meshes.get(handle).unwrap(); // NOTE: Mesh is already loaded
match Collider::from_bevy_mesh(mesh, shape) {
Some(collider) => {
commands.entity(child).insert(collider);
}
None => error!(
"Unable to generate collider from mesh {:?} with name {}",
mesh, name
),
}
}
}
});

commands.entity(entity).remove::<AsyncSceneCollider>();
}
}
}

/// Iterates over all descendants of the `entity` and applies `f`.
#[cfg(feature = "dim3")]
fn traverse_descendants(entity: Entity, children: &Query<&Children>, f: &mut impl FnMut(Entity)) {
if let Ok(entity_children) = children.get(entity) {
for child in entity_children.iter().copied() {
f(child);
traverse_descendants(child, children, f);
}
}
}

/// System responsible for creating new Rapier colliders from the related `bevy_rapier` components.
pub fn init_colliders(
mut commands: Commands,
Expand Down Expand Up @@ -1141,8 +1061,6 @@ pub fn update_colliding_entities(

#[cfg(test)]
mod tests {
#[cfg(feature = "dim3")]
use bevy::prelude::shape::{Capsule, Cube};
use bevy::{
asset::AssetPlugin,
core::CorePlugin,
Expand All @@ -1155,8 +1073,6 @@ mod tests {

use super::*;
use crate::plugin::{NoUserData, RapierPhysicsPlugin};
#[cfg(feature = "dim3")]
use crate::prelude::ComputedColliderShape;

#[test]
fn colliding_entities_updates() {
Expand Down Expand Up @@ -1244,93 +1160,6 @@ mod tests {
);
}

#[test]
#[cfg(feature = "dim3")]
fn async_collider_initializes() {
let mut app = App::new();
app.add_plugin(HeadlessRenderPlugin)
.add_system(init_async_colliders);

let mut meshes = app.world.resource_mut::<Assets<Mesh>>();
let cube = meshes.add(Cube::default().into());

let entity = app
.world
.spawn()
.insert(AsyncCollider {
handle: cube,
shape: ComputedColliderShape::TriMesh,
})
.id();

app.update();

let entity = app.world.entity(entity);
assert!(
entity.get::<Collider>().is_some(),
"Collider component should be added"
);
assert!(
entity.get::<AsyncCollider>().is_none(),
"AsyncCollider component should be removed after Collider component creation"
);
}

#[test]
#[cfg(feature = "dim3")]
fn async_scene_collider_initializes() {
let mut app = App::new();
app.add_plugin(HeadlessRenderPlugin)
.add_system(init_async_scene_colliders);

let mut meshes = app.world.resource_mut::<Assets<Mesh>>();
let cube_handle = meshes.add(Cube::default().into());
let capsule_handle = meshes.add(Capsule::default().into());
let cube = app
.world
.spawn()
.insert(Name::new("Cube"))
.insert(cube_handle)
.id();
let capsule = app
.world
.spawn()
.insert(Name::new("Capsule"))
.insert(capsule_handle)
.id();

let mut scenes = app.world.resource_mut::<Assets<Scene>>();
let scene = scenes.add(Scene::new(World::new()));

let mut named_shapes = bevy::utils::HashMap::new();
named_shapes.insert("Capsule".to_string(), None);
let parent = app
.world
.spawn()
.insert(AsyncSceneCollider {
handle: scene,
shape: Some(ComputedColliderShape::TriMesh),
named_shapes,
})
.push_children(&[cube, capsule])
.id();

app.update();

assert!(
app.world.entity(cube).get::<Collider>().is_some(),
"Collider component should be added for cube"
);
assert!(
app.world.entity(capsule).get::<Collider>().is_none(),
"Collider component shouldn't be added for capsule"
);
assert!(
app.world.entity(parent).get::<AsyncCollider>().is_none(),
"AsyncSceneCollider component should be removed after Collider components creation"
);
}

#[test]
fn transform_propagation() {
let mut app = App::new();
Expand Down

0 comments on commit d159770

Please sign in to comment.