From 28c581d465b48bb5084e9620aec744d96cb21c92 Mon Sep 17 00:00:00 2001 From: Kayh Date: Wed, 4 Sep 2024 17:19:15 -0400 Subject: [PATCH] collider fixes --- .../src/api/wired/physics/collider.rs | 16 +++- .../src/api/wired/physics/rigid_body.rs | 9 ++ .../src/api/wired/scene/gltf/node.rs | 82 +++++++++++++------ crates/unavi-scripting/src/state.rs | 24 +++--- wasm/example-unavi-shapes/src/lib.rs | 5 -- wasm/test-wired-scene/src/lib.rs | 5 +- wasm/test-wired-scene/src/node.rs | 17 +++- wasm/unavi-shapes/src/shapes/rectangle.rs | 6 +- 8 files changed, 111 insertions(+), 53 deletions(-) diff --git a/crates/unavi-scripting/src/api/wired/physics/collider.rs b/crates/unavi-scripting/src/api/wired/physics/collider.rs index ba991468d..35e9007e4 100644 --- a/crates/unavi-scripting/src/api/wired/physics/collider.rs +++ b/crates/unavi-scripting/src/api/wired/physics/collider.rs @@ -7,7 +7,10 @@ use crate::{ state::StoreState, }; -use super::bindings::wired::physics::types::{HostCollider, Shape}; +use super::bindings::{ + types::{ShapeCylinder, Vec3}, + wired::physics::types::{HostCollider, Shape}, +}; #[derive(Debug)] pub struct Collider { @@ -32,6 +35,17 @@ impl Collider { ref_count: RefCountCell::default(), } } + + /// Returns the equivalent Bevy component. + pub fn component(&self) -> avian3d::prelude::Collider { + match self.shape { + Shape::Cuboid(Vec3 { x, y, z }) => avian3d::prelude::Collider::cuboid(x, y, z), + Shape::Cylinder(ShapeCylinder { height, radius }) => { + avian3d::prelude::Collider::cylinder(radius, height) + } + Shape::Sphere(radius) => avian3d::prelude::Collider::sphere(radius), + } + } } impl HostCollider for StoreState { diff --git a/crates/unavi-scripting/src/api/wired/physics/rigid_body.rs b/crates/unavi-scripting/src/api/wired/physics/rigid_body.rs index 8858b0cc0..27826a0b2 100644 --- a/crates/unavi-scripting/src/api/wired/physics/rigid_body.rs +++ b/crates/unavi-scripting/src/api/wired/physics/rigid_body.rs @@ -29,6 +29,15 @@ impl RigidBody { rigid_body_type, } } + + /// Returns the equivalent Bevy component. + pub fn component(&self) -> avian3d::prelude::RigidBody { + match self.rigid_body_type { + RigidBodyType::Dynamic => avian3d::prelude::RigidBody::Dynamic, + RigidBodyType::Fixed => avian3d::prelude::RigidBody::Static, + RigidBodyType::Kinematic => avian3d::prelude::RigidBody::Kinematic, + } + } } impl RefCount for RigidBody { diff --git a/crates/unavi-scripting/src/api/wired/scene/gltf/node.rs b/crates/unavi-scripting/src/api/wired/scene/gltf/node.rs index 6f8346578..f601ea96b 100644 --- a/crates/unavi-scripting/src/api/wired/scene/gltf/node.rs +++ b/crates/unavi-scripting/src/api/wired/scene/gltf/node.rs @@ -1,5 +1,6 @@ use std::cell::Cell; +use avian3d::prelude::MassPropertiesBundle; use bevy::{ prelude::{Transform as BTransform, *}, utils::HashMap, @@ -12,9 +13,12 @@ use crate::{ utils::{RefCount, RefCountCell, RefResource}, wired::{ input::{bindings::InputHandler, input_handler::InputHandlerSender}, - math::bindings::types::{Transform, Vec3}, - physics::bindings::types::{Collider, RigidBody, RigidBodyType, Shape, ShapeCylinder}, - scene::bindings::node::{Host, HostNode}, + math::bindings::types::Transform, + physics::bindings::types::{Collider, RigidBody}, + scene::bindings::{ + node::{Host, HostNode}, + scene::Node, + }, }, }, state::{MaterialState, PrimitiveState, StoreState}, @@ -309,14 +313,25 @@ impl HostNode for StoreState { let node = self.table.get_mut(&self_)?; node.transform = value.into(); - self.node_insert( - self_.rep(), - BTransform { - translation: value.translation.into(), - rotation: value.rotation.into(), - scale: value.scale.into(), - }, - ); + let mut transform = BTransform { + translation: value.translation.into(), + rotation: value.rotation.into(), + scale: value.scale.into(), + }; + + // parry3d (used in avian physics) panics when scale is 0 + const ALMOST_ZERO: f32 = 10e-10; + if transform.scale.x == 0.0 { + transform.scale.x = ALMOST_ZERO; + } + if transform.scale.y == 0.0 { + transform.scale.y = ALMOST_ZERO; + } + if transform.scale.z == 0.0 { + transform.scale.z = ALMOST_ZERO; + } + + self.node_insert(self_.rep(), transform); Ok(()) } @@ -346,14 +361,7 @@ impl HostNode for StoreState { let collider = match &value { Some(value) => { let collider = self.table.get(value)?; - let collider = match collider.shape { - Shape::Cuboid(Vec3 { x, y, z }) => avian3d::prelude::Collider::cuboid(x, y, z), - Shape::Cylinder(ShapeCylinder { height, radius }) => { - avian3d::prelude::Collider::cylinder(radius, height) - } - Shape::Sphere(radius) => avian3d::prelude::Collider::sphere(radius), - }; - Some(collider) + Some(collider.component()) } None => None, }; @@ -361,6 +369,8 @@ impl HostNode for StoreState { let node = self.table.get_mut(&self_)?; node.collider = value; + compute_mass_properties(&self_, self)?; + self.node_insert_option(self_.rep(), collider); Ok(()) @@ -385,12 +395,7 @@ impl HostNode for StoreState { let rigid_body = match &value { Some(value) => { let rigid_body = self.table.get(value)?; - let rigid_body = match rigid_body.rigid_body_type { - RigidBodyType::Dynamic => avian3d::prelude::RigidBody::Dynamic, - RigidBodyType::Fixed => avian3d::prelude::RigidBody::Static, - RigidBodyType::Kinematic => avian3d::prelude::RigidBody::Kinematic, - }; - Some(rigid_body) + Some(rigid_body.component()) } None => None, }; @@ -398,6 +403,8 @@ impl HostNode for StoreState { let node = self.table.get_mut(&self_)?; node.rigid_body = value; + compute_mass_properties(&self_, self)?; + self.node_insert_option(self_.rep(), rigid_body); Ok(()) @@ -457,6 +464,31 @@ impl HostNode for StoreState { impl Host for StoreState {} +fn compute_mass_properties( + node_res: &Resource, + state: &mut StoreState, +) -> Result<(), ResourceTableError> { + let rep = node_res.rep(); + let node = state.table.get(node_res)?; + + if node.rigid_body.is_some() { + if let Some(collider) = &node.collider { + let collider = state.table.get(collider)?; + + state.node_insert( + rep, + MassPropertiesBundle::new_computed(&collider.component(), 1.0), + ); + } else { + state.node_insert(rep, MassPropertiesBundle::default()); + } + } else { + state.node_remove::(rep) + } + + Ok(()) +} + fn calc_global_transform( transform: BTransform, node: &NodeRes, diff --git a/crates/unavi-scripting/src/state.rs b/crates/unavi-scripting/src/state.rs index 478931704..5b73e0ad9 100644 --- a/crates/unavi-scripting/src/state.rs +++ b/crates/unavi-scripting/src/state.rs @@ -74,21 +74,9 @@ impl StoreState { T::from_res(res, &self.table) } - /// Inserts a component into the given node. - pub fn node_insert(&mut self, node: u32, value: T) { - let nodes = self.entities.nodes.clone(); - - self.commands.push(move |world: &mut World| { - let nodes = nodes.read().unwrap(); - let entity = nodes.get(&node).unwrap(); - let mut entity = world.entity_mut(*entity); - entity.insert(value); - }); - } - /// Inserts a component into the given node if the value is `Some`. /// If the value is `None`, removes the component from the entity. - pub fn node_insert_option(&mut self, node: u32, value: Option) { + pub fn node_insert_option(&mut self, node: u32, value: Option) { let nodes = self.entities.nodes.clone(); self.commands.push(move |world: &mut World| { @@ -103,6 +91,16 @@ impl StoreState { } }); } + + /// Inserts a component into the given node. + pub fn node_insert(&mut self, node: u32, value: T) { + self.node_insert_option(node, Some(value)) + } + + /// Removes a component from the given node. + pub fn node_remove(&mut self, node: u32) { + self.node_insert_option::(node, None) + } } #[derive(Default)] diff --git a/wasm/example-unavi-shapes/src/lib.rs b/wasm/example-unavi-shapes/src/lib.rs index a91043c88..ae0cec0d1 100644 --- a/wasm/example-unavi-shapes/src/lib.rs +++ b/wasm/example-unavi-shapes/src/lib.rs @@ -19,34 +19,29 @@ impl GuestScript for Script { { let cuboid = Cuboid::new(Vec3::new(1.0, 0.5, 1.5)).to_physics_node(); - assert!(cuboid.collider().is_some()); cuboid.set_transform(Transform::from_translation(Vec3::new(3.0, 0.0, 0.0))); scene.add_node(&cuboid); } { let sphere = Sphere::new_ico(0.5).to_physics_node(); - assert!(sphere.collider().is_some()); sphere.set_transform(Transform::from_translation(Vec3::new(1.5, 0.0, 2.0))); scene.add_node(&sphere); } { let sphere = Sphere::new_uv(0.5).to_physics_node(); - assert!(sphere.collider().is_some()); sphere.set_transform(Transform::from_translation(Vec3::new(1.5, 0.0, 0.0))); scene.add_node(&sphere); } { let cylinder = Cylinder::new(0.5, 1.0).to_physics_node(); - assert!(cylinder.collider().is_some()); scene.add_node(&cylinder); } { let rectangle = Rectangle::new(Vec2::splat(1.0)).to_physics_node(); - assert!(rectangle.collider().is_some()); rectangle.set_transform(Transform::from_translation(Vec3::new(-1.5, 0.0, 0.0))); scene.add_node(&rectangle); } diff --git a/wasm/test-wired-scene/src/lib.rs b/wasm/test-wired-scene/src/lib.rs index 0e926826e..faaa88776 100644 --- a/wasm/test-wired-scene/src/lib.rs +++ b/wasm/test-wired-scene/src/lib.rs @@ -12,8 +12,7 @@ mod scene; mod wired_math_impls; mod wired_scene_impls; -#[derive(Default)] -struct Script {} +struct Script; impl GuestScript for Script { fn new() -> Self { @@ -24,7 +23,7 @@ impl GuestScript for Script { node::test_node_api(); scene::test_scene_api(); - Script::default() + Script } fn update(&self, _delta: f32) { diff --git a/wasm/test-wired-scene/src/node.rs b/wasm/test-wired-scene/src/node.rs index f4244a82e..91797d3fe 100644 --- a/wasm/test-wired-scene/src/node.rs +++ b/wasm/test-wired-scene/src/node.rs @@ -1,10 +1,11 @@ use crate::{ bindings::wired::{ log::api::{log, LogLevel}, + physics::types::{Collider, RigidBodyType, Shape}, scene::{ gltf::Gltf, mesh::Mesh, - node::{Node, Transform}, + node::{Node, RigidBody, Transform}, }, }, panic_log, @@ -106,4 +107,18 @@ pub fn test_node_api() { ); panic_log(&err); } + + let collider = Collider::new(Shape::Sphere(0.5)); + node.set_collider(Some(&collider)); + assert!(node.collider().is_some()); + + let rigid_body = RigidBody::new(RigidBodyType::Dynamic); + node.set_rigid_body(Some(&rigid_body)); + assert!(node.rigid_body().is_some()); + + node.set_collider(None); + assert!(node.collider().is_none()); + + node.set_rigid_body(None); + assert!(node.rigid_body().is_none()); } diff --git a/wasm/unavi-shapes/src/shapes/rectangle.rs b/wasm/unavi-shapes/src/shapes/rectangle.rs index 9cdca906c..42f225346 100644 --- a/wasm/unavi-shapes/src/shapes/rectangle.rs +++ b/wasm/unavi-shapes/src/shapes/rectangle.rs @@ -9,8 +9,6 @@ use crate::bindings::{ }, }; -const COLLIDER_DEPTH: f32 = 0.0001; - pub struct Rectangle { size: RefCell, } @@ -41,9 +39,7 @@ impl GuestRectangle for Rectangle { let node = self.to_node(); let size = self.size(); node.set_collider(Some(&Collider::new(Shape::Cuboid(Vec3::new( - size.x, - size.y, - COLLIDER_DEPTH, + size.x, size.y, 0.0, ))))); node }