From 2a09d60327b630c8325960c32bc16082c3628179 Mon Sep 17 00:00:00 2001 From: hyunho lee Date: Mon, 3 Oct 2022 00:52:57 +0900 Subject: [PATCH 01/12] feat: add particle --- oxide_physics/Cargo.toml | 25 ++++++ oxide_physics/src/lib.rs | 10 +++ oxide_physics/src/particle.rs | 152 ++++++++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 oxide_physics/Cargo.toml create mode 100644 oxide_physics/src/lib.rs create mode 100644 oxide_physics/src/particle.rs diff --git a/oxide_physics/Cargo.toml b/oxide_physics/Cargo.toml new file mode 100644 index 0000000..08d4158 --- /dev/null +++ b/oxide_physics/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "oxide_physics" +version = "0.0.1" +authors = [ + "Chris Ohk ", + "Changseo Jang ", + "Yongwook Choi ", + "Chaneun Yeo ", + "Seokwon Moon ", + "Oxide Engine" +] +edition = "2021" +description = "Physics library for Oxide" + +repository = "https://github.com/OxideEngine/Oxide" + +license = "MIT" + +[lib] +name = "oxide_physics" +path = "src/lib.rs" + +[dependencies] +oxide_math = {path = "../oxide_math", version = "0.0.1"} +num-traits = "0.2" \ No newline at end of file diff --git a/oxide_physics/src/lib.rs b/oxide_physics/src/lib.rs new file mode 100644 index 0000000..3dc5c88 --- /dev/null +++ b/oxide_physics/src/lib.rs @@ -0,0 +1,10 @@ +pub mod particle; + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + let result = 2 + 2; + assert_eq!(result, 4); + } +} diff --git a/oxide_physics/src/particle.rs b/oxide_physics/src/particle.rs new file mode 100644 index 0000000..fc28927 --- /dev/null +++ b/oxide_physics/src/particle.rs @@ -0,0 +1,152 @@ +// use std::ops::Add; + +use oxide_math::commons::vector::*; +use oxide_math::commons::vector3::Vector3; +use num_traits::pow; + +struct Particle { + inverse_mass: f32, + damping: f32, + position: Vector3, + velocity: Vector3, + force_accum: Vector3, + acceleration: Vector3, +} + +impl Particle { + fn integrate(&mut self, duration: f32) { + // not to integrate things with zero mass + if self.inverse_mass <= 0.0f32 { + return ; + } + assert!(duration > 0.0); + + // update linear position + self.position.x = self.position.x + self.velocity.scale(duration).x; + self.position.y = self.position.y + self.velocity.scale(duration).y; + self.position.z = self.position.z + self.velocity.scale(duration).z; + + // work out the acceleration from the force + let mut resulting_acc = Vector3 { + x: self.acceleration.x, + y: self.acceleration.y, + z: self.acceleration.z, + }; + resulting_acc = resulting_acc + self.force_accum.scale(self.inverse_mass); + + // update linear velocity from the acceleration + self.velocity.x = self.velocity.x + resulting_acc.scale(duration).x; + self.velocity.y = self.velocity.y + resulting_acc.scale(duration).y; + self.velocity.z = self.velocity.z + resulting_acc.scale(duration).z; + + // impose drag + self.velocity = self.velocity.scale(pow(self.damping, duration as usize)); + + Particle::clear_accumulator(self); + } + + fn set_mass(&mut self, mass: f32) { + assert!(mass != 0.0f32); + self.inverse_mass = (1.0f32) / mass; + } + + fn get_mass(&mut self) -> f32 { + if self.inverse_mass == 0.0f32 { + f32::MAX + } else { + 1.0f32 / self.inverse_mass + } + } + + fn set_inverse_mass(&mut self, inverse_mass: f32) { + self.inverse_mass = inverse_mass; + } + + fn get_inverse_mass(&mut self) -> f32 { + self.inverse_mass + } + + fn has_finite_mass(&mut self) -> bool { + self.inverse_mass >= 0.0f32 + } + + fn set_damping(&mut self, damping: f32) { + self.damping = damping; + } + + fn get_damping(&mut self) -> f32 { + self.damping + } + + fn set_position(&mut self, position: &Vector3) { + self.position.x = position.x; + self.position.y = position.y; + self.position.z = position.z; + } + + fn set_position_by_coord(&mut self, x: f32, y: f32, z: f32) { + self.position.x = x; + self.position.y = y; + self.position.z = z; + } + + fn get_position(&mut self) -> &Vector3 { + &self.position + } + + fn set_velocity(&mut self, velocity: &Vector3) { + self.velocity.x = velocity.x; + self.velocity.y = velocity.y; + self.velocity.z = velocity.z; + } + + fn set_velocity_by_coord(&mut self, x: f32, y: f32, z: f32) { + self.velocity.x = x; + self.velocity.y = y; + self.velocity.z = z; + } + + fn get_velocity_into_vec(&mut self, velocity: &mut Vector3) { + velocity.x = self.velocity.x; + velocity.y = self.velocity.y; + velocity.z = self.velocity.z; + } + + fn get_velocity(&mut self) -> &Vector3 { + &self.velocity + } + + fn set_acceleration(&mut self, acceleration: &Vector3) { + self.acceleration.x = acceleration.x; + self.acceleration.y = acceleration.y; + self.acceleration.z = acceleration.z; + } + + fn set_acceleration_by_coord(&mut self, x: f32, y: f32, z: f32) { + self.acceleration.x = x; + self.acceleration.y = y; + self.acceleration.z = z; + } + + fn get_acceleration_into_vec(&mut self, acceleration: &mut Vector3) { + acceleration.x = self.acceleration.x; + acceleration.y = self.acceleration.y; + acceleration.z = self.acceleration.z; + } + + fn get_acceleration(&mut self) -> &Vector3 { + &self.acceleration + } + + fn clear_accumulator(&mut self) { + self.force_accum.x = 0.0f32; + self.force_accum.y = 0.0f32; + self.force_accum.z = 0.0f32; + } + + fn add_force(&mut self, force: &Vector3) { + self.force_accum.x += force.x; + self.force_accum.y += force.y; + self.force_accum.z += force.z; + } +} \ No newline at end of file From be7546c36ff970acd74c76a5017833b311c551a5 Mon Sep 17 00:00:00 2001 From: chiefmate Date: Sat, 4 Feb 2023 17:47:08 +0900 Subject: [PATCH 02/12] Work in progress: AABB --- oxide_physics/src/aabb.rs | 41 ++++++++++++++++++++++++++++ oxide_physics/src/bounding_volume.rs | 9 ++++++ oxide_physics/src/collision_world.rs | 7 +++++ oxide_physics/src/lib.rs | 2 +- oxide_physics/src/particle.rs | 17 ++++++------ oxide_physics/src/shape.rs | 20 ++++++++++++++ 6 files changed, 87 insertions(+), 9 deletions(-) create mode 100644 oxide_physics/src/aabb.rs create mode 100644 oxide_physics/src/bounding_volume.rs create mode 100644 oxide_physics/src/collision_world.rs create mode 100644 oxide_physics/src/shape.rs diff --git a/oxide_physics/src/aabb.rs b/oxide_physics/src/aabb.rs new file mode 100644 index 0000000..001fd9a --- /dev/null +++ b/oxide_physics/src/aabb.rs @@ -0,0 +1,41 @@ +use oxide_math::commons::vector::*; +use oxide_math::commons::vector3::Vector3; +use num_traits::pow; + +pub struct AABB { + pub mins: Vector3, + pub maxs: Vector3, +} + +pub fn aabb(s: &S) -> AABB +where + S: HasBoundingVolume +{ + s.local_bounding_volume() +} + +impl AABB { + pub fn new(mins: Vector3, maxs: Vector3) -> AABB { + AABB { mins: mins, maxs: maxs } + } + + pub fn mins(&self) -> &Vector3 { + &self.mins + } + + pub fn maxs(&self) -> &Vector3 { + &self.maxs + } +} + +impl BoundingVolume for AABB { + fn intersects(&self, other: &AABB) -> bool { + self.mins.x <= other.maxs.x && + self.maxs.x >= other.maxs.x && + self.mins.y <= other.maxs.y && + self.maxs.y >= other.maxs.y && + self.mins.z <= other.maxs.z && + self.maxs.z >= other.maxs.z + + } +} diff --git a/oxide_physics/src/bounding_volume.rs b/oxide_physics/src/bounding_volume.rs new file mode 100644 index 0000000..891de4c --- /dev/null +++ b/oxide_physics/src/bounding_volume.rs @@ -0,0 +1,9 @@ + +pub trait BoundingVolume { + // check if the bounding volume intersects with another one + fn intersects(&self, _: &Self) -> bool; +} + +pub trait HasBoundingVolume { + fn local_bounding_volume(&self) -> BV; +} diff --git a/oxide_physics/src/collision_world.rs b/oxide_physics/src/collision_world.rs new file mode 100644 index 0000000..78e8c58 --- /dev/null +++ b/oxide_physics/src/collision_world.rs @@ -0,0 +1,7 @@ + +pub struct CollisionWorld { + pub broad_phase: BroadPhaseObject, +} + +// type aliasing +pub BroadPhaseObject = Box diff --git a/oxide_physics/src/lib.rs b/oxide_physics/src/lib.rs index 3dc5c88..05f929a 100644 --- a/oxide_physics/src/lib.rs +++ b/oxide_physics/src/lib.rs @@ -3,7 +3,7 @@ pub mod particle; #[cfg(test)] mod tests { #[test] - fn it_works() { + fn aabb_works() { let result = 2 + 2; assert_eq!(result, 4); } diff --git a/oxide_physics/src/particle.rs b/oxide_physics/src/particle.rs index fc28927..78925e5 100644 --- a/oxide_physics/src/particle.rs +++ b/oxide_physics/src/particle.rs @@ -1,4 +1,5 @@ -// use std::ops::Add; +#![allow(dead_code)] +#![allow(unused_variables)] use oxide_math::commons::vector::*; use oxide_math::commons::vector3::Vector3; @@ -22,9 +23,9 @@ impl Particle { assert!(duration > 0.0); // update linear position - self.position.x = self.position.x + self.velocity.scale(duration).x; - self.position.y = self.position.y + self.velocity.scale(duration).y; - self.position.z = self.position.z + self.velocity.scale(duration).z; + self.position.x += self.velocity.scale(duration).x; + self.position.y += self.velocity.scale(duration).y; + self.position.z += self.velocity.scale(duration).z; // work out the acceleration from the force let mut resulting_acc = Vector3 { @@ -35,9 +36,9 @@ impl Particle { resulting_acc = resulting_acc + self.force_accum.scale(self.inverse_mass); // update linear velocity from the acceleration - self.velocity.x = self.velocity.x + resulting_acc.scale(duration).x; - self.velocity.y = self.velocity.y + resulting_acc.scale(duration).y; - self.velocity.z = self.velocity.z + resulting_acc.scale(duration).z; + self.velocity.x += resulting_acc.scale(duration).x; + self.velocity.y += resulting_acc.scale(duration).y; + self.velocity.z += resulting_acc.scale(duration).z; // impose drag self.velocity = self.velocity.scale(pow(self.damping, duration as usize)); @@ -149,4 +150,4 @@ impl Particle { self.force_accum.y += force.y; self.force_accum.z += force.z; } -} \ No newline at end of file +} diff --git a/oxide_physics/src/shape.rs b/oxide_physics/src/shape.rs new file mode 100644 index 0000000..587fa78 --- /dev/null +++ b/oxide_physics/src/shape.rs @@ -0,0 +1,20 @@ + +pub trait Shape { + fn local_aabb(&self) -> AABB; +} + +pub struct Ball { + radius: f64, +} + +impl Ball { + pub fn new(radius: f64) -> Ball { + assert!(radius > 0, "A ball radius must be positive."); + + Ball { radius } + } + + pub fn radius(&self) -> f64 { + self.radius + } +} From 91a06ee92d98400fcd8431de19727241a3f37e78 Mon Sep 17 00:00:00 2001 From: chiefmate Date: Sat, 18 Feb 2023 22:15:41 +0900 Subject: [PATCH 03/12] WIP: particle force generator --- oxide_physics/src/lib.rs | 1 + oxide_physics/src/particle.rs | 8 +-- oxide_physics/src/pfgen.rs | 99 +++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 oxide_physics/src/pfgen.rs diff --git a/oxide_physics/src/lib.rs b/oxide_physics/src/lib.rs index 05f929a..68dbb7c 100644 --- a/oxide_physics/src/lib.rs +++ b/oxide_physics/src/lib.rs @@ -1,4 +1,5 @@ pub mod particle; +pub mod pfgen; #[cfg(test)] mod tests { diff --git a/oxide_physics/src/particle.rs b/oxide_physics/src/particle.rs index 78925e5..33fb6e2 100644 --- a/oxide_physics/src/particle.rs +++ b/oxide_physics/src/particle.rs @@ -5,7 +5,7 @@ use oxide_math::commons::vector::*; use oxide_math::commons::vector3::Vector3; use num_traits::pow; -struct Particle { +pub struct Particle { inverse_mass: f32, damping: f32, position: Vector3, @@ -51,7 +51,7 @@ impl Particle { self.inverse_mass = (1.0f32) / mass; } - fn get_mass(&mut self) -> f32 { + pub fn get_mass(&self) -> f32 { if self.inverse_mass == 0.0f32 { f32::MAX } else { @@ -67,7 +67,7 @@ impl Particle { self.inverse_mass } - fn has_finite_mass(&mut self) -> bool { + pub fn has_finite_mass(&mut self) -> bool { self.inverse_mass >= 0.0f32 } @@ -145,7 +145,7 @@ impl Particle { self.force_accum.z = 0.0f32; } - fn add_force(&mut self, force: &Vector3) { + pub fn add_force(&mut self, force: &Vector3) { self.force_accum.x += force.x; self.force_accum.y += force.y; self.force_accum.z += force.z; diff --git a/oxide_physics/src/pfgen.rs b/oxide_physics/src/pfgen.rs new file mode 100644 index 0000000..f6ab817 --- /dev/null +++ b/oxide_physics/src/pfgen.rs @@ -0,0 +1,99 @@ + +use std::vec::Vec; +use crate::particle::*; +use oxide_math::commons::vector::*; +use oxide_math::commons::vector3::Vector3; + +type Real = f32; + +/* + * force generator trait + */ +pub trait ParticleForceGenerator { + /* + * interface to calculate and update the force + * to the given particle + */ + fn update_force(&self, particle: &mut Particle, duration: Real); +} + + +/* + * Registry for (Particle, Force Generator) pairs + */ +struct ParticleForceRegistration<'a> { + particle: &'a mut Particle, + fg: &'a dyn ParticleForceGenerator, +} + +struct ParticleForceRegistry<'a> { + registrations: Vec>, +} + +impl ParticleForceRegistry<'_> { + pub fn add(&self, particle: &Particle, fg: &dyn ParticleForceGenerator) { + /* TBD */ + } + + pub fn remove(&self, particle: &Particle, fg: &dyn ParticleForceGenerator) { + /* TBD */ + } + + pub fn clear(&self) { + /* TBD */ + } + + pub fn update_forces(&self, duration: Real) { + /* + * TBD + let reg_iter = self.registrations.iter(); + + for i in reg_iter { + i.fg.update_force(i.particle, duration); + } + */ + } +} + + +/* + * Gravity Force Generator + */ +struct ParticleGravity { + gravity: Vector3, +} + +impl ParticleGravity { + pub fn particle_gravity(&self, gravity: &Vector3) { + /* TBD */ + } +} + +impl ParticleForceGenerator for ParticleGravity { + fn update_force(&self, particle: &mut Particle, duration: Real) { + if !particle.has_finite_mass() { + return ; + } + particle.add_force(&self.gravity.scale(particle.get_mass())); + } +} + +/* + * Drag Force Generator + */ +struct ParticleDrag { + k1: Real, + k2: Real, +} + +impl ParticleDrag { + pub fn particle_drag(&self, k1: Real, k2:Real) { + /* TBD */ + } +} + +impl ParticleForceGenerator for ParticleDrag { + fn update_force(&self, particle: &mut Particle, duration: Real) { + /* TBD */ + } +} From 4a2aa63f1b02f0bf8c8ea21fd1e3d9fac6c5e2b5 Mon Sep 17 00:00:00 2001 From: chiefmate Date: Mon, 27 Feb 2023 22:55:19 +0900 Subject: [PATCH 04/12] add: ParticleSet, ParticleForceRegistration --- oxide_physics/Cargo.toml | 3 +- oxide_physics/src/aabb.rs | 1 - ...nding_volume.rs => collide_broad_phase.rs} | 4 + oxide_physics/src/lib.rs | 1 + oxide_physics/src/particle.rs | 122 ++++++++++++------ oxide_physics/src/pfgen.rs | 84 ++++++------ 6 files changed, 130 insertions(+), 85 deletions(-) rename oxide_physics/src/{bounding_volume.rs => collide_broad_phase.rs} (81%) diff --git a/oxide_physics/Cargo.toml b/oxide_physics/Cargo.toml index 08d4158..db4f4f2 100644 --- a/oxide_physics/Cargo.toml +++ b/oxide_physics/Cargo.toml @@ -22,4 +22,5 @@ path = "src/lib.rs" [dependencies] oxide_math = {path = "../oxide_math", version = "0.0.1"} -num-traits = "0.2" \ No newline at end of file +num-traits = "0.2" +generational-arena = "0.2" \ No newline at end of file diff --git a/oxide_physics/src/aabb.rs b/oxide_physics/src/aabb.rs index 001fd9a..89b3434 100644 --- a/oxide_physics/src/aabb.rs +++ b/oxide_physics/src/aabb.rs @@ -36,6 +36,5 @@ impl BoundingVolume for AABB { self.maxs.y >= other.maxs.y && self.mins.z <= other.maxs.z && self.maxs.z >= other.maxs.z - } } diff --git a/oxide_physics/src/bounding_volume.rs b/oxide_physics/src/collide_broad_phase.rs similarity index 81% rename from oxide_physics/src/bounding_volume.rs rename to oxide_physics/src/collide_broad_phase.rs index 891de4c..2f98255 100644 --- a/oxide_physics/src/bounding_volume.rs +++ b/oxide_physics/src/collide_broad_phase.rs @@ -1,4 +1,8 @@ +struct PotentialContact { + body: RigidBody, +} + pub trait BoundingVolume { // check if the bounding volume intersects with another one fn intersects(&self, _: &Self) -> bool; diff --git a/oxide_physics/src/lib.rs b/oxide_physics/src/lib.rs index 68dbb7c..8bea5c1 100644 --- a/oxide_physics/src/lib.rs +++ b/oxide_physics/src/lib.rs @@ -1,5 +1,6 @@ pub mod particle; pub mod pfgen; +pub mod collide_broad_phase; #[cfg(test)] mod tests { diff --git a/oxide_physics/src/particle.rs b/oxide_physics/src/particle.rs index 33fb6e2..5204d66 100644 --- a/oxide_physics/src/particle.rs +++ b/oxide_physics/src/particle.rs @@ -5,11 +5,14 @@ use oxide_math::commons::vector::*; use oxide_math::commons::vector3::Vector3; use num_traits::pow; +extern crate generational_arena; +use generational_arena::Arena; + pub struct Particle { inverse_mass: f32, damping: f32, position: Vector3, - velocity: Vector3, + pub velocity: Vector3, force_accum: Vector3, acceleration: Vector3, } @@ -28,12 +31,12 @@ impl Particle { self.position.z += self.velocity.scale(duration).z; // work out the acceleration from the force - let mut resulting_acc = Vector3 { - x: self.acceleration.x, - y: self.acceleration.y, - z: self.acceleration.z, + let delta = self.force_accum.scale(self.inverse_mass); + let resulting_acc = Vector3 { + x: self.acceleration.x + delta.x, + y: self.acceleration.y + delta.y, + z: self.acceleration.z + delta.z, }; - resulting_acc = resulting_acc + self.force_accum.scale(self.inverse_mass); // update linear velocity from the acceleration self.velocity.x += resulting_acc.scale(duration).x; @@ -67,7 +70,7 @@ impl Particle { self.inverse_mass } - pub fn has_finite_mass(&mut self) -> bool { + pub fn has_finite_mass(&self) -> bool { self.inverse_mass >= 0.0f32 } @@ -75,39 +78,47 @@ impl Particle { self.damping = damping; } - fn get_damping(&mut self) -> f32 { + fn get_damping(&self) -> f32 { self.damping } fn set_position(&mut self, position: &Vector3) { - self.position.x = position.x; - self.position.y = position.y; - self.position.z = position.z; + self.position = Vector3 { + x: position.x, + y: position.y, + z: position.z, + }; } fn set_position_by_coord(&mut self, x: f32, y: f32, z: f32) { - self.position.x = x; - self.position.y = y; - self.position.z = z; + self.position = Vector3 { + x, + y, + z, + } } - fn get_position(&mut self) -> &Vector3 { + fn get_position(&self) -> &Vector3 { &self.position } fn set_velocity(&mut self, velocity: &Vector3) { - self.velocity.x = velocity.x; - self.velocity.y = velocity.y; - self.velocity.z = velocity.z; + self.velocity = Vector3 { + x: velocity.x, + y: velocity.y, + z: velocity.z, + }; } fn set_velocity_by_coord(&mut self, x: f32, y: f32, z: f32) { - self.velocity.x = x; - self.velocity.y = y; - self.velocity.z = z; + self.velocity = Vector3 { + x, + y, + z, + } } - fn get_velocity_into_vec(&mut self, velocity: &mut Vector3) { + fn get_velocity_into_vec(&self, velocity: &mut Vector3) { velocity.x = self.velocity.x; velocity.y = self.velocity.y; velocity.z = self.velocity.z; @@ -118,36 +129,75 @@ impl Particle { } fn set_acceleration(&mut self, acceleration: &Vector3) { - self.acceleration.x = acceleration.x; - self.acceleration.y = acceleration.y; - self.acceleration.z = acceleration.z; + self.acceleration = Vector3 { + x: acceleration.x, + y: acceleration.y, + z: acceleration.z, + } } fn set_acceleration_by_coord(&mut self, x: f32, y: f32, z: f32) { - self.acceleration.x = x; - self.acceleration.y = y; - self.acceleration.z = z; + self.acceleration = Vector3 { + x, + y, + z, + } } - fn get_acceleration_into_vec(&mut self, acceleration: &mut Vector3) { + fn get_acceleration_into_vec(&self, acceleration: &mut Vector3) { acceleration.x = self.acceleration.x; acceleration.y = self.acceleration.y; acceleration.z = self.acceleration.z; } - fn get_acceleration(&mut self) -> &Vector3 { + fn get_acceleration(&self) -> &Vector3 { &self.acceleration } fn clear_accumulator(&mut self) { - self.force_accum.x = 0.0f32; - self.force_accum.y = 0.0f32; - self.force_accum.z = 0.0f32; + self.force_accum = Vector3 { + x: 0.0f32, + y: 0.0f32, + z: 0.0f32, + }; } pub fn add_force(&mut self, force: &Vector3) { - self.force_accum.x += force.x; - self.force_accum.y += force.y; - self.force_accum.z += force.z; + self.force_accum = Vector3 { + x: self.force_accum.x + force.x, + y: self.force_accum.y + force.y, + z: self.force_accum.z + force.z, + }; } } + +// The default particle set containing all the particles added to the world +// Uses arena to avoid ABA problem +pub struct DefaultParticleSet { + particles: Arena>, + removed: Vec, +} + +impl DefaultParticleSet { + // Creates an empty set + pub fn new() -> Self { + DefaultParticleSet { + particles: Arena::new(), + removed: Vec::new(), + } + } + + // Adds a particle to this set + pub fn insert(&mut self, particle: Particle) -> DefaultParticleHandle { + self.particles.insert(Box::new(particle)) + } + + // Removes a particle from this set + pub fn remove(&mut self, particle_handle: DefaultParticleHandle) -> Option> { + let result = self.particles.remove(particle_handle)?; + self.removed.push(particle_handle); + Some(result) + } +} + +pub type DefaultParticleHandle = generational_arena::Index; \ No newline at end of file diff --git a/oxide_physics/src/pfgen.rs b/oxide_physics/src/pfgen.rs index f6ab817..328dc2a 100644 --- a/oxide_physics/src/pfgen.rs +++ b/oxide_physics/src/pfgen.rs @@ -1,10 +1,10 @@ - use std::vec::Vec; use crate::particle::*; use oxide_math::commons::vector::*; use oxide_math::commons::vector3::Vector3; -type Real = f32; +extern crate generational_arena; +use generational_arena::Arena; /* * force generator trait @@ -14,48 +14,44 @@ pub trait ParticleForceGenerator { * interface to calculate and update the force * to the given particle */ - fn update_force(&self, particle: &mut Particle, duration: Real); + fn update_force(&self, particle: &mut Particle, duration: f32); } - /* * Registry for (Particle, Force Generator) pairs + * Holds all particles and associated force generators */ -struct ParticleForceRegistration<'a> { - particle: &'a mut Particle, - fg: &'a dyn ParticleForceGenerator, +struct ParticleForceRegistration { + particle: DefaultParticleHandle, + fg: DefaultForceGeneratorHandle, } -struct ParticleForceRegistry<'a> { - registrations: Vec>, +pub type DefaultForceGeneratorHandle = generational_arena::Index; + +pub struct ParticleForceRegistry { + registrations: Vec, } -impl ParticleForceRegistry<'_> { - pub fn add(&self, particle: &Particle, fg: &dyn ParticleForceGenerator) { - /* TBD */ +impl ParticleForceRegistry { + pub fn add(&self, particle: DefaultParticleHandle, fg: DefaultForceGeneratorHandle) { + /* NOT implemented */ } - - pub fn remove(&self, particle: &Particle, fg: &dyn ParticleForceGenerator) { - /* TBD */ + + pub fn remove(&self, particle: DefaultParticleHandle, fg: DefaultForceGeneratorHandle) { + /* NOT implemented */ } pub fn clear(&self) { - /* TBD */ + /* NOT implemented */ } - pub fn update_forces(&self, duration: Real) { - /* - * TBD - let reg_iter = self.registrations.iter(); - - for i in reg_iter { - i.fg.update_force(i.particle, duration); - } - */ + pub fn update_forces(&self, duration: f32) { + // for i in self.registrations.iter_mut() { + // i.fg.update_force(i.particle, duration); + // } } } - /* * Gravity Force Generator */ @@ -63,18 +59,11 @@ struct ParticleGravity { gravity: Vector3, } -impl ParticleGravity { - pub fn particle_gravity(&self, gravity: &Vector3) { - /* TBD */ - } -} - impl ParticleForceGenerator for ParticleGravity { - fn update_force(&self, particle: &mut Particle, duration: Real) { - if !particle.has_finite_mass() { - return ; - } - particle.add_force(&self.gravity.scale(particle.get_mass())); + fn update_force(&self, particle: &mut Particle, duration: f32) { + if particle.has_finite_mass() { + particle.add_force(&self.gravity.scale(particle.get_mass())); + } } } @@ -82,18 +71,19 @@ impl ParticleForceGenerator for ParticleGravity { * Drag Force Generator */ struct ParticleDrag { - k1: Real, - k2: Real, -} - -impl ParticleDrag { - pub fn particle_drag(&self, k1: Real, k2:Real) { - /* TBD */ - } + k1: f32, + k2: f32, } impl ParticleForceGenerator for ParticleDrag { - fn update_force(&self, particle: &mut Particle, duration: Real) { - /* TBD */ + fn update_force(&self, particle: &mut Particle, duration: f32) { + let force: &Vector3 = &particle.velocity; + + // Calculate the total drag coefficient + let drag_coeff: f32 = self.k1 * force.get_length() + self.k2 * force.get_length() * force.get_length(); + + // Calculate the final force and apply it + let final_force = force.normalize().scale(-drag_coeff); + particle.add_force(&final_force); } } From 4097a02c7bfc9ea948a1f8d9e3cdf084c097617e Mon Sep 17 00:00:00 2001 From: hyunho lee Date: Sat, 18 Mar 2023 20:26:37 +0900 Subject: [PATCH 05/12] add: AABB for ball and cuboid --- oxide_physics/src/aabb.rs | 65 +++++++++++++++++++----- oxide_physics/src/aabb_ball.rs | 33 ++++++++++++ oxide_physics/src/aabb_cuboid.rs | 22 ++++++++ oxide_physics/src/collide_broad_phase.rs | 25 ++++++--- oxide_physics/src/collision_world.rs | 7 --- oxide_physics/src/lib.rs | 6 +++ oxide_physics/src/particle.rs | 6 +++ oxide_physics/src/shape.rs | 46 +++++++++++++++-- 8 files changed, 178 insertions(+), 32 deletions(-) create mode 100644 oxide_physics/src/aabb_ball.rs create mode 100644 oxide_physics/src/aabb_cuboid.rs delete mode 100644 oxide_physics/src/collision_world.rs diff --git a/oxide_physics/src/aabb.rs b/oxide_physics/src/aabb.rs index 89b3434..55242c6 100644 --- a/oxide_physics/src/aabb.rs +++ b/oxide_physics/src/aabb.rs @@ -1,40 +1,81 @@ -use oxide_math::commons::vector::*; +use crate::collide_broad_phase::{BoundingVolume, HasBoundingVolume}; use oxide_math::commons::vector3::Vector3; -use num_traits::pow; pub struct AABB { pub mins: Vector3, pub maxs: Vector3, } -pub fn aabb(s: &S) -> AABB +pub fn aabb(shape: &S, tv: Vector3) -> AABB where - S: HasBoundingVolume + S: HasBoundingVolume { - s.local_bounding_volume() + shape.bounding_volume(tv) +} + +pub fn local_aabb(shape: &S) -> AABB +where + S: HasBoundingVolume +{ + shape.local_bounding_volume() } impl AABB { pub fn new(mins: Vector3, maxs: Vector3) -> AABB { - AABB { mins: mins, maxs: maxs } + AABB { mins, maxs } } - pub fn mins(&self) -> &Vector3 { - &self.mins + pub fn mins(&self) -> Vector3 { + Vector3 { + x: self.mins.x, + y: self.mins.y, + z: self.mins.z, + } } - pub fn maxs(&self) -> &Vector3 { - &self.maxs + pub fn maxs(&self) -> Vector3 { + Vector3 { + x: self.maxs.x, + y: self.maxs.y, + z: self.maxs.z, + } } } impl BoundingVolume for AABB { + // check if the bounding volume 'bv' intersects with self fn intersects(&self, other: &AABB) -> bool { self.mins.x <= other.maxs.x && - self.maxs.x >= other.maxs.x && self.mins.y <= other.maxs.y && - self.maxs.y >= other.maxs.y && self.mins.z <= other.maxs.z && + self.maxs.x >= other.mins.x && + self.maxs.y >= other.mins.y && + self.maxs.z >= other.mins.z + } + + // check if self contains the 'bv' + fn contains(&self, other: &AABB) -> bool { + self.mins.x <= other.mins.x && + self.mins.y <= other.mins.y && + self.mins.z <= other.mins.z && + self.maxs.x >= other.maxs.x && + self.maxs.y >= other.maxs.y && self.maxs.z >= other.maxs.z } + + // merge this bounding volume with the other 'bv' + fn merged(&self, other: &AABB) -> AABB { + AABB { + mins: Vector3 { + x: self.mins.x.min(other.mins.x), + y: self.mins.y.min(other.mins.y), + z: self.mins.z.min(other.mins.z), + }, + maxs: Vector3 { + x: self.maxs.x.max(other.maxs.x), + y: self.maxs.y.max(other.maxs.y), + z: self.maxs.z.max(other.maxs.z), + }, + } + } } diff --git a/oxide_physics/src/aabb_ball.rs b/oxide_physics/src/aabb_ball.rs new file mode 100644 index 0000000..4e53250 --- /dev/null +++ b/oxide_physics/src/aabb_ball.rs @@ -0,0 +1,33 @@ +use crate::collide_broad_phase::HasBoundingVolume; +use crate::shape::Ball; +use crate::aabb::AABB; +use oxide_math::commons::vector3::Vector3; + +pub fn ball_aabb(center: Vector3, radius: f32) -> AABB { + AABB::new( + Vector3 { + x: center.x - radius, + y: center.y - radius, + z: center.z - radius + }, + Vector3 { + x: center.x + radius, + y: center.y + radius, + z: center.z + radius + } + ) +} + +pub fn local_ball_aabb(radius: f32) -> AABB { + ball_aabb(Vector3 {x: 0.0, y: 0.0, z: 0.0}, radius) +} + +impl HasBoundingVolume for Ball { + fn bounding_volume(&self, tv: Vector3) -> AABB { + ball_aabb(tv, self.radius()) + } + + fn local_bounding_volume(&self) -> AABB { + local_ball_aabb(self.radius()) + } +} \ No newline at end of file diff --git a/oxide_physics/src/aabb_cuboid.rs b/oxide_physics/src/aabb_cuboid.rs new file mode 100644 index 0000000..5cb665b --- /dev/null +++ b/oxide_physics/src/aabb_cuboid.rs @@ -0,0 +1,22 @@ +use crate::collide_broad_phase::HasBoundingVolume; +use crate::shape::Cuboid; +use crate::aabb::AABB; +use oxide_math::commons::vector3::Vector3; + +impl HasBoundingVolume for Cuboid { + fn bounding_volume(&self, tv: Vector3) -> AABB { + let tv2 = Vector3 { + x: tv.x, + y: tv.y, + z: tv.z, + }; + AABB::new( + self.mins() + tv, + self.maxs() + tv2, + ) + } + + fn local_bounding_volume(&self) -> AABB { + self.bounding_volume(Vector3 {x: 0.0, y: 0.0, z: 0.0}) + } +} \ No newline at end of file diff --git a/oxide_physics/src/collide_broad_phase.rs b/oxide_physics/src/collide_broad_phase.rs index 2f98255..a8005de 100644 --- a/oxide_physics/src/collide_broad_phase.rs +++ b/oxide_physics/src/collide_broad_phase.rs @@ -1,13 +1,22 @@ - -struct PotentialContact { - body: RigidBody, -} +use oxide_math::commons::vector3::Vector3; pub trait BoundingVolume { - // check if the bounding volume intersects with another one - fn intersects(&self, _: &Self) -> bool; + // check if the bounding volume 'bv' intersects with self + fn intersects(&self, bv: &Self) -> bool; + + // check if self contains the 'bv' + fn contains(&self, bv: &Self) -> bool; + + // merge this bounding volume with the other 'bv' + fn merged(&self, bv: &Self) -> Self; } -pub trait HasBoundingVolume { - fn local_bounding_volume(&self) -> BV; +pub trait HasBoundingVolume { + // TBD: rotation by 4x4 matrix + // bounding volume of 'self' translated by 'tv' + fn bounding_volume(&self, tv: Vector3) -> BV; + + fn local_bounding_volume(&self) -> BV { + self.bounding_volume(Vector3 {x: 0.0, y: 0.0, z: 0.0}) + } } diff --git a/oxide_physics/src/collision_world.rs b/oxide_physics/src/collision_world.rs deleted file mode 100644 index 78e8c58..0000000 --- a/oxide_physics/src/collision_world.rs +++ /dev/null @@ -1,7 +0,0 @@ - -pub struct CollisionWorld { - pub broad_phase: BroadPhaseObject, -} - -// type aliasing -pub BroadPhaseObject = Box diff --git a/oxide_physics/src/lib.rs b/oxide_physics/src/lib.rs index 8bea5c1..bbc6ea2 100644 --- a/oxide_physics/src/lib.rs +++ b/oxide_physics/src/lib.rs @@ -1,6 +1,12 @@ pub mod particle; pub mod pfgen; + +pub mod shape; + pub mod collide_broad_phase; +pub mod aabb; +mod aabb_ball; +mod aabb_cuboid; #[cfg(test)] mod tests { diff --git a/oxide_physics/src/particle.rs b/oxide_physics/src/particle.rs index 5204d66..e7666d7 100644 --- a/oxide_physics/src/particle.rs +++ b/oxide_physics/src/particle.rs @@ -200,4 +200,10 @@ impl DefaultParticleSet { } } +impl Default for DefaultParticleSet { + fn default() -> Self { + Self::new() + } +} + pub type DefaultParticleHandle = generational_arena::Index; \ No newline at end of file diff --git a/oxide_physics/src/shape.rs b/oxide_physics/src/shape.rs index 587fa78..44b0f39 100644 --- a/oxide_physics/src/shape.rs +++ b/oxide_physics/src/shape.rs @@ -1,20 +1,56 @@ +use oxide_math::commons::vector3::Vector3; +use crate::aabb::AABB; pub trait Shape { - fn local_aabb(&self) -> AABB; + fn bounding_volume(&self) -> AABB; + fn local_bounding_volume(&self, tv: Vector3) -> AABB; } pub struct Ball { - radius: f64, + radius: f32, +} + +// x, y, and z are the half-extent of the cuboid +pub struct Cuboid { + x: f32, + y: f32, + z: f32, } impl Ball { - pub fn new(radius: f64) -> Ball { - assert!(radius > 0, "A ball radius must be positive."); + pub fn new(radius: f32) -> Self { + assert!(radius > 0.0, "A ball radius must be positive."); Ball { radius } } - pub fn radius(&self) -> f64 { + pub fn radius(&self) -> f32 { self.radius } } + +impl Cuboid { + pub fn new(position: &Vector3) -> Self { + Cuboid { + x: position.x, + y: position.y, + z: position.z, + } + } + + pub fn mins(&self) -> Vector3 { + Vector3 { + x: -self.x, + y: -self.y, + z: -self.z + } + } + + pub fn maxs(&self) -> Vector3 { + Vector3 { + x: self.x, + y: self.y, + z: self.z + } + } +} \ No newline at end of file From 6a35f788673049329a98a13a9c773ac9a2db9ca8 Mon Sep 17 00:00:00 2001 From: hyunho lee Date: Sat, 18 Mar 2023 21:54:55 +0900 Subject: [PATCH 06/12] style: fmt --- oxide_physics/src/aabb.rs | 32 +++---- oxide_physics/src/aabb_ball.rs | 19 ++-- oxide_physics/src/aabb_cuboid.rs | 15 +-- oxide_physics/src/collide_broad_phase.rs | 6 +- oxide_physics/src/lib.rs | 2 +- oxide_physics/src/particle.rs | 112 ++++++++++------------- oxide_physics/src/pfgen.rs | 27 +++--- oxide_physics/src/shape.rs | 8 +- 8 files changed, 111 insertions(+), 110 deletions(-) diff --git a/oxide_physics/src/aabb.rs b/oxide_physics/src/aabb.rs index 55242c6..b1d461e 100644 --- a/oxide_physics/src/aabb.rs +++ b/oxide_physics/src/aabb.rs @@ -8,14 +8,14 @@ pub struct AABB { pub fn aabb(shape: &S, tv: Vector3) -> AABB where - S: HasBoundingVolume + S: HasBoundingVolume, { shape.bounding_volume(tv) } pub fn local_aabb(shape: &S) -> AABB where - S: HasBoundingVolume + S: HasBoundingVolume, { shape.local_bounding_volume() } @@ -32,35 +32,35 @@ impl AABB { z: self.mins.z, } } - + pub fn maxs(&self) -> Vector3 { Vector3 { x: self.maxs.x, y: self.maxs.y, z: self.maxs.z, } - } + } } impl BoundingVolume for AABB { // check if the bounding volume 'bv' intersects with self fn intersects(&self, other: &AABB) -> bool { - self.mins.x <= other.maxs.x && - self.mins.y <= other.maxs.y && - self.mins.z <= other.maxs.z && - self.maxs.x >= other.mins.x && - self.maxs.y >= other.mins.y && - self.maxs.z >= other.mins.z + self.mins.x <= other.maxs.x + && self.mins.y <= other.maxs.y + && self.mins.z <= other.maxs.z + && self.maxs.x >= other.mins.x + && self.maxs.y >= other.mins.y + && self.maxs.z >= other.mins.z } // check if self contains the 'bv' fn contains(&self, other: &AABB) -> bool { - self.mins.x <= other.mins.x && - self.mins.y <= other.mins.y && - self.mins.z <= other.mins.z && - self.maxs.x >= other.maxs.x && - self.maxs.y >= other.maxs.y && - self.maxs.z >= other.maxs.z + self.mins.x <= other.mins.x + && self.mins.y <= other.mins.y + && self.mins.z <= other.mins.z + && self.maxs.x >= other.maxs.x + && self.maxs.y >= other.maxs.y + && self.maxs.z >= other.maxs.z } // merge this bounding volume with the other 'bv' diff --git a/oxide_physics/src/aabb_ball.rs b/oxide_physics/src/aabb_ball.rs index 4e53250..fc0c777 100644 --- a/oxide_physics/src/aabb_ball.rs +++ b/oxide_physics/src/aabb_ball.rs @@ -1,6 +1,6 @@ +use crate::aabb::AABB; use crate::collide_broad_phase::HasBoundingVolume; use crate::shape::Ball; -use crate::aabb::AABB; use oxide_math::commons::vector3::Vector3; pub fn ball_aabb(center: Vector3, radius: f32) -> AABB { @@ -8,18 +8,25 @@ pub fn ball_aabb(center: Vector3, radius: f32) -> AABB { Vector3 { x: center.x - radius, y: center.y - radius, - z: center.z - radius + z: center.z - radius, }, Vector3 { x: center.x + radius, y: center.y + radius, - z: center.z + radius - } + z: center.z + radius, + }, ) } pub fn local_ball_aabb(radius: f32) -> AABB { - ball_aabb(Vector3 {x: 0.0, y: 0.0, z: 0.0}, radius) + ball_aabb( + Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + radius, + ) } impl HasBoundingVolume for Ball { @@ -30,4 +37,4 @@ impl HasBoundingVolume for Ball { fn local_bounding_volume(&self) -> AABB { local_ball_aabb(self.radius()) } -} \ No newline at end of file +} diff --git a/oxide_physics/src/aabb_cuboid.rs b/oxide_physics/src/aabb_cuboid.rs index 5cb665b..e6337d0 100644 --- a/oxide_physics/src/aabb_cuboid.rs +++ b/oxide_physics/src/aabb_cuboid.rs @@ -1,6 +1,6 @@ +use crate::aabb::AABB; use crate::collide_broad_phase::HasBoundingVolume; use crate::shape::Cuboid; -use crate::aabb::AABB; use oxide_math::commons::vector3::Vector3; impl HasBoundingVolume for Cuboid { @@ -10,13 +10,14 @@ impl HasBoundingVolume for Cuboid { y: tv.y, z: tv.z, }; - AABB::new( - self.mins() + tv, - self.maxs() + tv2, - ) + AABB::new(self.mins() + tv, self.maxs() + tv2) } fn local_bounding_volume(&self) -> AABB { - self.bounding_volume(Vector3 {x: 0.0, y: 0.0, z: 0.0}) + self.bounding_volume(Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }) } -} \ No newline at end of file +} diff --git a/oxide_physics/src/collide_broad_phase.rs b/oxide_physics/src/collide_broad_phase.rs index a8005de..4b6805f 100644 --- a/oxide_physics/src/collide_broad_phase.rs +++ b/oxide_physics/src/collide_broad_phase.rs @@ -17,6 +17,10 @@ pub trait HasBoundingVolume { fn bounding_volume(&self, tv: Vector3) -> BV; fn local_bounding_volume(&self) -> BV { - self.bounding_volume(Vector3 {x: 0.0, y: 0.0, z: 0.0}) + self.bounding_volume(Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }) } } diff --git a/oxide_physics/src/lib.rs b/oxide_physics/src/lib.rs index bbc6ea2..414b2b5 100644 --- a/oxide_physics/src/lib.rs +++ b/oxide_physics/src/lib.rs @@ -3,10 +3,10 @@ pub mod pfgen; pub mod shape; -pub mod collide_broad_phase; pub mod aabb; mod aabb_ball; mod aabb_cuboid; +pub mod collide_broad_phase; #[cfg(test)] mod tests { diff --git a/oxide_physics/src/particle.rs b/oxide_physics/src/particle.rs index e7666d7..ea9ae3f 100644 --- a/oxide_physics/src/particle.rs +++ b/oxide_physics/src/particle.rs @@ -1,9 +1,9 @@ #![allow(dead_code)] #![allow(unused_variables)] +use num_traits::pow; use oxide_math::commons::vector::*; use oxide_math::commons::vector3::Vector3; -use num_traits::pow; extern crate generational_arena; use generational_arena::Arena; @@ -21,7 +21,7 @@ impl Particle { fn integrate(&mut self, duration: f32) { // not to integrate things with zero mass if self.inverse_mass <= 0.0f32 { - return ; + return; } assert!(duration > 0.0); @@ -31,7 +31,7 @@ impl Particle { self.position.z += self.velocity.scale(duration).z; // work out the acceleration from the force - let delta = self.force_accum.scale(self.inverse_mass); + let delta = self.force_accum.scale(self.inverse_mass); let resulting_acc = Vector3 { x: self.acceleration.x + delta.x, y: self.acceleration.y + delta.y, @@ -84,38 +84,30 @@ impl Particle { fn set_position(&mut self, position: &Vector3) { self.position = Vector3 { - x: position.x, - y: position.y, - z: position.z, - }; + x: position.x, + y: position.y, + z: position.z, + }; } fn set_position_by_coord(&mut self, x: f32, y: f32, z: f32) { - self.position = Vector3 { - x, - y, - z, - } + self.position = Vector3 { x, y, z } } fn get_position(&self) -> &Vector3 { - &self.position + &self.position } fn set_velocity(&mut self, velocity: &Vector3) { self.velocity = Vector3 { - x: velocity.x, - y: velocity.y, - z: velocity.z, - }; + x: velocity.x, + y: velocity.y, + z: velocity.z, + }; } fn set_velocity_by_coord(&mut self, x: f32, y: f32, z: f32) { - self.velocity = Vector3 { - x, - y, - z, - } + self.velocity = Vector3 { x, y, z } } fn get_velocity_into_vec(&self, velocity: &mut Vector3) { @@ -130,18 +122,14 @@ impl Particle { fn set_acceleration(&mut self, acceleration: &Vector3) { self.acceleration = Vector3 { - x: acceleration.x, - y: acceleration.y, - z: acceleration.z, - } + x: acceleration.x, + y: acceleration.y, + z: acceleration.z, + } } fn set_acceleration_by_coord(&mut self, x: f32, y: f32, z: f32) { - self.acceleration = Vector3 { - x, - y, - z, - } + self.acceleration = Vector3 { x, y, z } } fn get_acceleration_into_vec(&self, acceleration: &mut Vector3) { @@ -156,48 +144,48 @@ impl Particle { fn clear_accumulator(&mut self) { self.force_accum = Vector3 { - x: 0.0f32, - y: 0.0f32, - z: 0.0f32, - }; + x: 0.0f32, + y: 0.0f32, + z: 0.0f32, + }; } pub fn add_force(&mut self, force: &Vector3) { - self.force_accum = Vector3 { - x: self.force_accum.x + force.x, - y: self.force_accum.y + force.y, - z: self.force_accum.z + force.z, - }; + self.force_accum = Vector3 { + x: self.force_accum.x + force.x, + y: self.force_accum.y + force.y, + z: self.force_accum.z + force.z, + }; } } // The default particle set containing all the particles added to the world // Uses arena to avoid ABA problem pub struct DefaultParticleSet { - particles: Arena>, - removed: Vec, + particles: Arena>, + removed: Vec, } impl DefaultParticleSet { - // Creates an empty set - pub fn new() -> Self { - DefaultParticleSet { - particles: Arena::new(), - removed: Vec::new(), - } - } - - // Adds a particle to this set - pub fn insert(&mut self, particle: Particle) -> DefaultParticleHandle { - self.particles.insert(Box::new(particle)) - } - - // Removes a particle from this set - pub fn remove(&mut self, particle_handle: DefaultParticleHandle) -> Option> { - let result = self.particles.remove(particle_handle)?; - self.removed.push(particle_handle); - Some(result) - } + // Creates an empty set + pub fn new() -> Self { + DefaultParticleSet { + particles: Arena::new(), + removed: Vec::new(), + } + } + + // Adds a particle to this set + pub fn insert(&mut self, particle: Particle) -> DefaultParticleHandle { + self.particles.insert(Box::new(particle)) + } + + // Removes a particle from this set + pub fn remove(&mut self, particle_handle: DefaultParticleHandle) -> Option> { + let result = self.particles.remove(particle_handle)?; + self.removed.push(particle_handle); + Some(result) + } } impl Default for DefaultParticleSet { @@ -206,4 +194,4 @@ impl Default for DefaultParticleSet { } } -pub type DefaultParticleHandle = generational_arena::Index; \ No newline at end of file +pub type DefaultParticleHandle = generational_arena::Index; diff --git a/oxide_physics/src/pfgen.rs b/oxide_physics/src/pfgen.rs index 328dc2a..b0f7a02 100644 --- a/oxide_physics/src/pfgen.rs +++ b/oxide_physics/src/pfgen.rs @@ -1,7 +1,7 @@ -use std::vec::Vec; use crate::particle::*; use oxide_math::commons::vector::*; use oxide_math::commons::vector3::Vector3; +use std::vec::Vec; extern crate generational_arena; use generational_arena::Arena; @@ -19,7 +19,7 @@ pub trait ParticleForceGenerator { /* * Registry for (Particle, Force Generator) pairs - * Holds all particles and associated force generators + * Holds all particles and associated force generators */ struct ParticleForceRegistration { particle: DefaultParticleHandle, @@ -29,20 +29,20 @@ struct ParticleForceRegistration { pub type DefaultForceGeneratorHandle = generational_arena::Index; pub struct ParticleForceRegistry { - registrations: Vec, + registrations: Vec, } impl ParticleForceRegistry { pub fn add(&self, particle: DefaultParticleHandle, fg: DefaultForceGeneratorHandle) { - /* NOT implemented */ + /* NOT implemented */ } pub fn remove(&self, particle: DefaultParticleHandle, fg: DefaultForceGeneratorHandle) { - /* NOT implemented */ + /* NOT implemented */ } pub fn clear(&self) { - /* NOT implemented */ + /* NOT implemented */ } pub fn update_forces(&self, duration: f32) { @@ -62,8 +62,8 @@ struct ParticleGravity { impl ParticleForceGenerator for ParticleGravity { fn update_force(&self, particle: &mut Particle, duration: f32) { if particle.has_finite_mass() { - particle.add_force(&self.gravity.scale(particle.get_mass())); - } + particle.add_force(&self.gravity.scale(particle.get_mass())); + } } } @@ -79,11 +79,12 @@ impl ParticleForceGenerator for ParticleDrag { fn update_force(&self, particle: &mut Particle, duration: f32) { let force: &Vector3 = &particle.velocity; - // Calculate the total drag coefficient - let drag_coeff: f32 = self.k1 * force.get_length() + self.k2 * force.get_length() * force.get_length(); + // Calculate the total drag coefficient + let drag_coeff: f32 = + self.k1 * force.get_length() + self.k2 * force.get_length() * force.get_length(); - // Calculate the final force and apply it - let final_force = force.normalize().scale(-drag_coeff); - particle.add_force(&final_force); + // Calculate the final force and apply it + let final_force = force.normalize().scale(-drag_coeff); + particle.add_force(&final_force); } } diff --git a/oxide_physics/src/shape.rs b/oxide_physics/src/shape.rs index 44b0f39..ab5600f 100644 --- a/oxide_physics/src/shape.rs +++ b/oxide_physics/src/shape.rs @@ -1,5 +1,5 @@ -use oxide_math::commons::vector3::Vector3; use crate::aabb::AABB; +use oxide_math::commons::vector3::Vector3; pub trait Shape { fn bounding_volume(&self) -> AABB; @@ -42,7 +42,7 @@ impl Cuboid { Vector3 { x: -self.x, y: -self.y, - z: -self.z + z: -self.z, } } @@ -50,7 +50,7 @@ impl Cuboid { Vector3 { x: self.x, y: self.y, - z: self.z + z: self.z, } } -} \ No newline at end of file +} From 44bfeed971cfd57bdb468d65a8316e83a0ceb8bf Mon Sep 17 00:00:00 2001 From: Hyunho Lee Date: Thu, 29 Jun 2023 15:46:21 +0900 Subject: [PATCH 07/12] refactor: particle and pfgen --- oxide_physics/src/particle.rs | 115 ++++++++++------------------------ 1 file changed, 34 insertions(+), 81 deletions(-) diff --git a/oxide_physics/src/particle.rs b/oxide_physics/src/particle.rs index ea9ae3f..66f3fd1 100644 --- a/oxide_physics/src/particle.rs +++ b/oxide_physics/src/particle.rs @@ -18,12 +18,20 @@ pub struct Particle { } impl Particle { - fn integrate(&mut self, duration: f32) { - // not to integrate things with zero mass + // returns integrated velocity + fn integrate(&mut self, duration: f32) -> Result { + // not to integrate things with infinite mass if self.inverse_mass <= 0.0f32 { - return; + return Ok( + Vector3 { + x: self.velocity.x, + y: self.velocity.y, + z: self.velocity.z, + }); + } + if duration <= 0.0 { + return Err("Cannot integrate with zero duration") } - assert!(duration > 0.0); // update linear position self.position.x += self.velocity.scale(duration).x; @@ -47,13 +55,25 @@ impl Particle { self.velocity = self.velocity.scale(pow(self.damping, duration as usize)); Particle::clear_accumulator(self); + + Ok( + Vector3 { + x: self.velocity.x, + y: self.velocity.y, + z: self.velocity.z, + }) } - fn set_mass(&mut self, mass: f32) { - assert!(mass != 0.0f32); + // Returns inverse of mass + fn set_mass(&mut self, mass: f32) -> Result { + if mass == 0.0f32 { + return Err("Cannot set zero mass") + } self.inverse_mass = (1.0f32) / mass; + Ok(self.inverse_mass) } + // Returns mass of the particle pub fn get_mass(&self) -> f32 { if self.inverse_mass == 0.0f32 { f32::MAX @@ -62,84 +82,17 @@ impl Particle { } } - fn set_inverse_mass(&mut self, inverse_mass: f32) { - self.inverse_mass = inverse_mass; - } - - fn get_inverse_mass(&mut self) -> f32 { - self.inverse_mass - } - - pub fn has_finite_mass(&self) -> bool { - self.inverse_mass >= 0.0f32 - } - - fn set_damping(&mut self, damping: f32) { - self.damping = damping; - } - - fn get_damping(&self) -> f32 { - self.damping - } - - fn set_position(&mut self, position: &Vector3) { - self.position = Vector3 { - x: position.x, - y: position.y, - z: position.z, - }; - } - - fn set_position_by_coord(&mut self, x: f32, y: f32, z: f32) { - self.position = Vector3 { x, y, z } - } - - fn get_position(&self) -> &Vector3 { - &self.position - } - - fn set_velocity(&mut self, velocity: &Vector3) { - self.velocity = Vector3 { - x: velocity.x, - y: velocity.y, - z: velocity.z, - }; - } - - fn set_velocity_by_coord(&mut self, x: f32, y: f32, z: f32) { - self.velocity = Vector3 { x, y, z } - } - - fn get_velocity_into_vec(&self, velocity: &mut Vector3) { - velocity.x = self.velocity.x; - velocity.y = self.velocity.y; - velocity.z = self.velocity.z; - } - - fn get_velocity(&mut self) -> &Vector3 { - &self.velocity - } - - fn set_acceleration(&mut self, acceleration: &Vector3) { - self.acceleration = Vector3 { - x: acceleration.x, - y: acceleration.y, - z: acceleration.z, + // Returns the velocity of the particle + pub fn get_velocity(&self) -> Vector3 { + Vector3 { + x: self.velocity.x, + y: self.velocity.y, + z: self.velocity.z, } } - fn set_acceleration_by_coord(&mut self, x: f32, y: f32, z: f32) { - self.acceleration = Vector3 { x, y, z } - } - - fn get_acceleration_into_vec(&self, acceleration: &mut Vector3) { - acceleration.x = self.acceleration.x; - acceleration.y = self.acceleration.y; - acceleration.z = self.acceleration.z; - } - - fn get_acceleration(&self) -> &Vector3 { - &self.acceleration + pub fn has_finite_mass(&self) -> bool { + self.inverse_mass > 0.0f32 } fn clear_accumulator(&mut self) { From 215b524db3b037807d8c277b75ef1e0c9541be56 Mon Sep 17 00:00:00 2001 From: chiefmate Date: Thu, 29 Jun 2023 16:19:33 +0900 Subject: [PATCH 08/12] fix: fmt, clippy --- oxide_physics/src/particle.rs | 26 ++++++++++++-------------- oxide_physics/src/pfgen.rs | 11 +++++++---- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/oxide_physics/src/particle.rs b/oxide_physics/src/particle.rs index 66f3fd1..0def2c1 100644 --- a/oxide_physics/src/particle.rs +++ b/oxide_physics/src/particle.rs @@ -22,15 +22,14 @@ impl Particle { fn integrate(&mut self, duration: f32) -> Result { // not to integrate things with infinite mass if self.inverse_mass <= 0.0f32 { - return Ok( - Vector3 { - x: self.velocity.x, - y: self.velocity.y, - z: self.velocity.z, - }); + return Ok(Vector3 { + x: self.velocity.x, + y: self.velocity.y, + z: self.velocity.z, + }); } if duration <= 0.0 { - return Err("Cannot integrate with zero duration") + return Err("Cannot integrate with zero duration"); } // update linear position @@ -56,18 +55,17 @@ impl Particle { Particle::clear_accumulator(self); - Ok( - Vector3 { - x: self.velocity.x, - y: self.velocity.y, - z: self.velocity.z, - }) + Ok(Vector3 { + x: self.velocity.x, + y: self.velocity.y, + z: self.velocity.z, + }) } // Returns inverse of mass fn set_mass(&mut self, mass: f32) -> Result { if mass == 0.0f32 { - return Err("Cannot set zero mass") + return Err("Cannot set zero mass"); } self.inverse_mass = (1.0f32) / mass; Ok(self.inverse_mass) diff --git a/oxide_physics/src/pfgen.rs b/oxide_physics/src/pfgen.rs index b0f7a02..cdde920 100644 --- a/oxide_physics/src/pfgen.rs +++ b/oxide_physics/src/pfgen.rs @@ -1,10 +1,12 @@ +#![allow(dead_code)] +#![allow(unused_variables)] + use crate::particle::*; use oxide_math::commons::vector::*; use oxide_math::commons::vector3::Vector3; use std::vec::Vec; extern crate generational_arena; -use generational_arena::Arena; /* * force generator trait @@ -34,21 +36,22 @@ pub struct ParticleForceRegistry { impl ParticleForceRegistry { pub fn add(&self, particle: DefaultParticleHandle, fg: DefaultForceGeneratorHandle) { - /* NOT implemented */ + todo!() } pub fn remove(&self, particle: DefaultParticleHandle, fg: DefaultForceGeneratorHandle) { - /* NOT implemented */ + todo!() } pub fn clear(&self) { - /* NOT implemented */ + todo!() } pub fn update_forces(&self, duration: f32) { // for i in self.registrations.iter_mut() { // i.fg.update_force(i.particle, duration); // } + todo!() } } From 0d6e9838839567a190c026dc284e9d7d37041591 Mon Sep 17 00:00:00 2001 From: chiefmate Date: Sat, 8 Jul 2023 17:56:36 +0900 Subject: [PATCH 09/12] add: AABB tests --- oxide_physics/src/aabb.rs | 46 ++++++++++++++++++++++++++ oxide_physics/src/aabb_ball.rs | 26 +++++++++++++++ oxide_physics/src/aabb_cuboid.rs | 25 ++++++++++++++ oxide_physics/src/shape.rs | 57 +++++++++++++++++++++++++++----- 4 files changed, 145 insertions(+), 9 deletions(-) diff --git a/oxide_physics/src/aabb.rs b/oxide_physics/src/aabb.rs index b1d461e..8fffe62 100644 --- a/oxide_physics/src/aabb.rs +++ b/oxide_physics/src/aabb.rs @@ -1,6 +1,8 @@ use crate::collide_broad_phase::{BoundingVolume, HasBoundingVolume}; use oxide_math::commons::vector3::Vector3; +#[derive(Debug)] +#[derive(PartialEq)] pub struct AABB { pub mins: Vector3, pub maxs: Vector3, @@ -79,3 +81,47 @@ impl BoundingVolume for AABB { } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::shape::Ball; + + #[test] + fn test_intersects() { + let ball = Ball::new(1.0).unwrap(); + let ball_aabb0 = ball.local_bounding_volume(); + let ball_aabb1 = ball.bounding_volume(Vector3 { x: 0.5, y: 0.5, z: 0.5 }); + let ball_aabb2 = ball.bounding_volume(Vector3 { x: 1.5, y: 1.5, z: 1.5 }); + let ball_aabb3 = ball.bounding_volume(Vector3 { x: 3.0, y: 1.0, z: 1.0 }); + assert_eq!(true, ball_aabb0.intersects(&ball_aabb1)); + assert_eq!(true, ball_aabb0.intersects(&ball_aabb2)); + assert_eq!(false, ball_aabb0.intersects(&ball_aabb3)); + } + + #[test] + fn test_contains() { + let ball = Ball::new(1.0).unwrap(); + let bigball = Ball::new(3.0).unwrap(); + let ball_aabb0 = ball.local_bounding_volume(); + let ball_aabb1 = ball.bounding_volume(Vector3 { x: 0.5, y: 0.5, z: 0.5 }); + let ball_aabb2 = ball.bounding_volume(Vector3 { x: 1.5, y: 1.5, z: 1.5 }); + let ball_aabb3 = ball.bounding_volume(Vector3 { x: 3.0, y: 1.0, z: 1.0 }); + let bigball_aabb = bigball.local_bounding_volume(); + assert_eq!(false, ball_aabb0.contains(&ball_aabb1)); + assert_eq!(true, bigball_aabb.contains(&ball_aabb2)); + assert_eq!(false, bigball_aabb.contains(&ball_aabb3)); + } + + #[test] + fn test_merged() { + let ball = Ball::new(1.0).unwrap(); + let bigball = Ball::new(3.0).unwrap(); + let ball_aabb = ball.bounding_volume(Vector3 { x: 3.0, y: 1.0, z: 1.0 }); + let bigball_aabb = bigball.local_bounding_volume(); + assert_eq!(ball_aabb.merged(&bigball_aabb), AABB { + mins: Vector3 { x: -3.0, y: -3.0, z: -3.0 }, + maxs: Vector3 { x: 4.0, y: 3.0, z: 3.0 }, + }); + } +} diff --git a/oxide_physics/src/aabb_ball.rs b/oxide_physics/src/aabb_ball.rs index fc0c777..2c18909 100644 --- a/oxide_physics/src/aabb_ball.rs +++ b/oxide_physics/src/aabb_ball.rs @@ -38,3 +38,29 @@ impl HasBoundingVolume for Ball { local_ball_aabb(self.radius()) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ball_aabb() { + let ball = Ball::new(4.0).unwrap(); + let ball_aabb = ball.bounding_volume(Vector3 { x: 3.0, y: 4.0, z: 5.0 }); + assert_eq!(ball_aabb, AABB { + mins: Vector3 { x: -1.0, y: 0.0, z: 1.0 }, + maxs: Vector3 { x: 7.0, y: 8.0, z: 9.0 }, + }); + + } + + #[test] + fn test_local_aabb() { + let ball = Ball::new(4.0).unwrap(); + let ball_aabb = ball.local_bounding_volume(); + assert_eq!(ball_aabb, AABB { + mins: Vector3 { x: -4.0, y: -4.0, z: -4.0 }, + maxs: Vector3 { x: 4.0, y: 4.0, z: 4.0 }, + }); + } +} diff --git a/oxide_physics/src/aabb_cuboid.rs b/oxide_physics/src/aabb_cuboid.rs index e6337d0..8e01fa4 100644 --- a/oxide_physics/src/aabb_cuboid.rs +++ b/oxide_physics/src/aabb_cuboid.rs @@ -21,3 +21,28 @@ impl HasBoundingVolume for Cuboid { }) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_cuboid_aabb() { + let cuboid = Cuboid::new(Vector3 { x: 3.0, y: 4.0, z: 5.0 }).unwrap(); + let cuboid_aabb = cuboid.bounding_volume(Vector3 { x: 3.0, y: 4.0, z: 5.0 }); + assert_eq!(cuboid_aabb, AABB { + mins: Vector3 { x: 0.0, y: 0.0, z: 0.0 }, + maxs: Vector3 { x: 6.0, y: 8.0, z: 10.0 }, + }); + } + + #[test] + fn test_local_aabb() { + let cuboid = Cuboid::new(Vector3 { x: 3.0, y: 4.0, z: 5.0 }).unwrap(); + let cuboid_aabb = cuboid.local_bounding_volume(); + assert_eq!(cuboid_aabb, AABB { + mins: Vector3 { x: -3.0, y: -4.0, z: -5.0 }, + maxs: Vector3 { x: 3.0, y: 4.0, z: 5.0 }, + }); + } +} diff --git a/oxide_physics/src/shape.rs b/oxide_physics/src/shape.rs index ab5600f..64e9477 100644 --- a/oxide_physics/src/shape.rs +++ b/oxide_physics/src/shape.rs @@ -6,10 +6,14 @@ pub trait Shape { fn local_bounding_volume(&self, tv: Vector3) -> AABB; } +#[derive(Debug)] +#[derive(PartialEq)] pub struct Ball { radius: f32, } +#[derive(Debug)] +#[derive(PartialEq)] // x, y, and z are the half-extent of the cuboid pub struct Cuboid { x: f32, @@ -18,10 +22,12 @@ pub struct Cuboid { } impl Ball { - pub fn new(radius: f32) -> Self { - assert!(radius > 0.0, "A ball radius must be positive."); - - Ball { radius } + pub fn new(radius: f32) -> Result { + if radius <= 0.0 { + Err("A ball radius must be positive.") + } else { + Ok(Ball { radius }) + } } pub fn radius(&self) -> f32 { @@ -30,11 +36,16 @@ impl Ball { } impl Cuboid { - pub fn new(position: &Vector3) -> Self { - Cuboid { - x: position.x, - y: position.y, - z: position.z, + // x, y, and z are the half-extent of the cuboid + pub fn new(position: Vector3) -> Result { + if position.x == 0.0 || position.y == 0.0 || position.z == 0.0 { + Err("Cuboid's edge must be bigger than 0") + } else { + Ok(Cuboid { + x: position.x.abs(), + y: position.y.abs(), + z: position.z.abs(), + }) } } @@ -54,3 +65,31 @@ impl Cuboid { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ball() { + let ball = Ball::new(4.0).unwrap(); + assert_eq!(Ball { radius: 4.0 }, ball); + assert_eq!(4.0, ball.radius()); + } + + #[test] + fn test_cuboid() { + let cuboid = Cuboid::new(Vector3 { + x: 2.0, + y: -4.0, + z: 6.0, + }).unwrap(); + assert_eq!(Cuboid { + x: 2.0, + y: 4.0, + z: 6.0, + }, cuboid); + assert_eq!(Vector3 { x: -2.0, y: -4.0, z: -6.0}, cuboid.mins()); + assert_eq!(Vector3 { x: 2.0, y: 4.0, z: 6.0}, cuboid.maxs()); + } +} From a5e9254013d0ca681df71f8780eab1a5f4c3724c Mon Sep 17 00:00:00 2001 From: chiefmate Date: Sat, 8 Jul 2023 18:30:19 +0900 Subject: [PATCH 10/12] add: particle tests --- oxide_physics/src/aabb.rs | 64 +++++++-- oxide_physics/src/aabb_ball.rs | 43 +++++-- oxide_physics/src/aabb_cuboid.rs | 56 ++++++-- oxide_physics/src/lib.rs | 9 -- oxide_physics/src/particle.rs | 215 +++++++++++++++++++++++++++++++ oxide_physics/src/shape.rs | 40 ++++-- 6 files changed, 374 insertions(+), 53 deletions(-) diff --git a/oxide_physics/src/aabb.rs b/oxide_physics/src/aabb.rs index 8fffe62..6da969d 100644 --- a/oxide_physics/src/aabb.rs +++ b/oxide_physics/src/aabb.rs @@ -1,8 +1,7 @@ use crate::collide_broad_phase::{BoundingVolume, HasBoundingVolume}; use oxide_math::commons::vector3::Vector3; -#[derive(Debug)] -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] pub struct AABB { pub mins: Vector3, pub maxs: Vector3, @@ -91,9 +90,21 @@ mod tests { fn test_intersects() { let ball = Ball::new(1.0).unwrap(); let ball_aabb0 = ball.local_bounding_volume(); - let ball_aabb1 = ball.bounding_volume(Vector3 { x: 0.5, y: 0.5, z: 0.5 }); - let ball_aabb2 = ball.bounding_volume(Vector3 { x: 1.5, y: 1.5, z: 1.5 }); - let ball_aabb3 = ball.bounding_volume(Vector3 { x: 3.0, y: 1.0, z: 1.0 }); + let ball_aabb1 = ball.bounding_volume(Vector3 { + x: 0.5, + y: 0.5, + z: 0.5, + }); + let ball_aabb2 = ball.bounding_volume(Vector3 { + x: 1.5, + y: 1.5, + z: 1.5, + }); + let ball_aabb3 = ball.bounding_volume(Vector3 { + x: 3.0, + y: 1.0, + z: 1.0, + }); assert_eq!(true, ball_aabb0.intersects(&ball_aabb1)); assert_eq!(true, ball_aabb0.intersects(&ball_aabb2)); assert_eq!(false, ball_aabb0.intersects(&ball_aabb3)); @@ -104,9 +115,21 @@ mod tests { let ball = Ball::new(1.0).unwrap(); let bigball = Ball::new(3.0).unwrap(); let ball_aabb0 = ball.local_bounding_volume(); - let ball_aabb1 = ball.bounding_volume(Vector3 { x: 0.5, y: 0.5, z: 0.5 }); - let ball_aabb2 = ball.bounding_volume(Vector3 { x: 1.5, y: 1.5, z: 1.5 }); - let ball_aabb3 = ball.bounding_volume(Vector3 { x: 3.0, y: 1.0, z: 1.0 }); + let ball_aabb1 = ball.bounding_volume(Vector3 { + x: 0.5, + y: 0.5, + z: 0.5, + }); + let ball_aabb2 = ball.bounding_volume(Vector3 { + x: 1.5, + y: 1.5, + z: 1.5, + }); + let ball_aabb3 = ball.bounding_volume(Vector3 { + x: 3.0, + y: 1.0, + z: 1.0, + }); let bigball_aabb = bigball.local_bounding_volume(); assert_eq!(false, ball_aabb0.contains(&ball_aabb1)); assert_eq!(true, bigball_aabb.contains(&ball_aabb2)); @@ -117,11 +140,26 @@ mod tests { fn test_merged() { let ball = Ball::new(1.0).unwrap(); let bigball = Ball::new(3.0).unwrap(); - let ball_aabb = ball.bounding_volume(Vector3 { x: 3.0, y: 1.0, z: 1.0 }); - let bigball_aabb = bigball.local_bounding_volume(); - assert_eq!(ball_aabb.merged(&bigball_aabb), AABB { - mins: Vector3 { x: -3.0, y: -3.0, z: -3.0 }, - maxs: Vector3 { x: 4.0, y: 3.0, z: 3.0 }, + let ball_aabb = ball.bounding_volume(Vector3 { + x: 3.0, + y: 1.0, + z: 1.0, }); + let bigball_aabb = bigball.local_bounding_volume(); + assert_eq!( + ball_aabb.merged(&bigball_aabb), + AABB { + mins: Vector3 { + x: -3.0, + y: -3.0, + z: -3.0 + }, + maxs: Vector3 { + x: 4.0, + y: 3.0, + z: 3.0 + }, + } + ); } } diff --git a/oxide_physics/src/aabb_ball.rs b/oxide_physics/src/aabb_ball.rs index 2c18909..3afd68d 100644 --- a/oxide_physics/src/aabb_ball.rs +++ b/oxide_physics/src/aabb_ball.rs @@ -46,21 +46,46 @@ mod tests { #[test] fn test_ball_aabb() { let ball = Ball::new(4.0).unwrap(); - let ball_aabb = ball.bounding_volume(Vector3 { x: 3.0, y: 4.0, z: 5.0 }); - assert_eq!(ball_aabb, AABB { - mins: Vector3 { x: -1.0, y: 0.0, z: 1.0 }, - maxs: Vector3 { x: 7.0, y: 8.0, z: 9.0 }, + let ball_aabb = ball.bounding_volume(Vector3 { + x: 3.0, + y: 4.0, + z: 5.0, }); - + assert_eq!( + ball_aabb, + AABB { + mins: Vector3 { + x: -1.0, + y: 0.0, + z: 1.0 + }, + maxs: Vector3 { + x: 7.0, + y: 8.0, + z: 9.0 + }, + } + ); } #[test] fn test_local_aabb() { let ball = Ball::new(4.0).unwrap(); let ball_aabb = ball.local_bounding_volume(); - assert_eq!(ball_aabb, AABB { - mins: Vector3 { x: -4.0, y: -4.0, z: -4.0 }, - maxs: Vector3 { x: 4.0, y: 4.0, z: 4.0 }, - }); + assert_eq!( + ball_aabb, + AABB { + mins: Vector3 { + x: -4.0, + y: -4.0, + z: -4.0 + }, + maxs: Vector3 { + x: 4.0, + y: 4.0, + z: 4.0 + }, + } + ); } } diff --git a/oxide_physics/src/aabb_cuboid.rs b/oxide_physics/src/aabb_cuboid.rs index 8e01fa4..6dd5022 100644 --- a/oxide_physics/src/aabb_cuboid.rs +++ b/oxide_physics/src/aabb_cuboid.rs @@ -28,21 +28,57 @@ mod tests { #[test] fn test_cuboid_aabb() { - let cuboid = Cuboid::new(Vector3 { x: 3.0, y: 4.0, z: 5.0 }).unwrap(); - let cuboid_aabb = cuboid.bounding_volume(Vector3 { x: 3.0, y: 4.0, z: 5.0 }); - assert_eq!(cuboid_aabb, AABB { - mins: Vector3 { x: 0.0, y: 0.0, z: 0.0 }, - maxs: Vector3 { x: 6.0, y: 8.0, z: 10.0 }, + let cuboid = Cuboid::new(Vector3 { + x: 3.0, + y: 4.0, + z: 5.0, + }) + .unwrap(); + let cuboid_aabb = cuboid.bounding_volume(Vector3 { + x: 3.0, + y: 4.0, + z: 5.0, }); + assert_eq!( + cuboid_aabb, + AABB { + mins: Vector3 { + x: 0.0, + y: 0.0, + z: 0.0 + }, + maxs: Vector3 { + x: 6.0, + y: 8.0, + z: 10.0 + }, + } + ); } #[test] fn test_local_aabb() { - let cuboid = Cuboid::new(Vector3 { x: 3.0, y: 4.0, z: 5.0 }).unwrap(); + let cuboid = Cuboid::new(Vector3 { + x: 3.0, + y: 4.0, + z: 5.0, + }) + .unwrap(); let cuboid_aabb = cuboid.local_bounding_volume(); - assert_eq!(cuboid_aabb, AABB { - mins: Vector3 { x: -3.0, y: -4.0, z: -5.0 }, - maxs: Vector3 { x: 3.0, y: 4.0, z: 5.0 }, - }); + assert_eq!( + cuboid_aabb, + AABB { + mins: Vector3 { + x: -3.0, + y: -4.0, + z: -5.0 + }, + maxs: Vector3 { + x: 3.0, + y: 4.0, + z: 5.0 + }, + } + ); } } diff --git a/oxide_physics/src/lib.rs b/oxide_physics/src/lib.rs index 414b2b5..37c23ab 100644 --- a/oxide_physics/src/lib.rs +++ b/oxide_physics/src/lib.rs @@ -7,12 +7,3 @@ pub mod aabb; mod aabb_ball; mod aabb_cuboid; pub mod collide_broad_phase; - -#[cfg(test)] -mod tests { - #[test] - fn aabb_works() { - let result = 2 + 2; - assert_eq!(result, 4); - } -} diff --git a/oxide_physics/src/particle.rs b/oxide_physics/src/particle.rs index 0def2c1..61b5635 100644 --- a/oxide_physics/src/particle.rs +++ b/oxide_physics/src/particle.rs @@ -18,6 +18,30 @@ pub struct Particle { } impl Particle { + // default mass is set to 1.0 + fn new(position: Vector3) -> Particle { + Particle { + inverse_mass: 1.0, + damping: 1.0, + position: Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + velocity: position, + force_accum: Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + acceleration: Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + } + } + // returns integrated velocity fn integrate(&mut self, duration: f32) -> Result { // not to integrate things with infinite mass @@ -146,3 +170,194 @@ impl Default for DefaultParticleSet { } pub type DefaultParticleHandle = generational_arena::Index; + +#[cfg(test)] +mod tests { + use oxide_math::components::velocity::Velocity; + + use super::*; + + #[test] + fn test_set_mass() { + let mut p = Particle::new(Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }); + if let Err(msg) = p.set_mass(5.0) { + panic!("{}", msg); + } + assert_eq!(0.2, p.inverse_mass); + } + + #[test] + #[should_panic] + fn test_bad_set_mass() { + let mut p = Particle::new(Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }); + if let Err(msg) = p.set_mass(0.0) { + panic!("{}", msg); + } + } + + #[test] + fn test_get_mass() { + let mut p = Particle::new(Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }); + if let Err(msg) = p.set_mass(5.0) { + panic!("{}", msg); + } + assert_eq!(5.0, p.get_mass()); + } + + #[test] + fn test_get_velocity() { + let mut p = Particle::new(Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }); + if let Err(msg) = p.set_mass(5.0) { + panic!("{}", msg); + } + let f = Vector3 { + x: 2.0, + y: 0.0, + z: 0.0, + }; + p.add_force(&f); + p.integrate(1.0).unwrap(); + assert_eq!( + Vector3 { + x: 2.0, + y: 0.0, + z: 0.0 + }, + p.get_velocity() + ); + } + + fn test_has_finite_mass() { + let mut p = Particle::new(Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }); + assert_eq!(true, p.has_finite_mass()); + let mut q = Particle { + inverse_mass: 0.0, + damping: 1.0, + position: Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + velocity: Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + force_accum: Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + acceleration: Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + }; + assert_eq!(false, q.has_finite_mass()); + } + + #[test] + fn test_particle1() { + let mut p = Particle::new(Vector3 { + x: 0.0, + y: 0.0, + z: 0.0, + }); + assert_eq!( + p.position, + Vector3 { + x: 0.0, + y: 0.0, + z: 0.0 + } + ); + assert_eq!( + p.get_velocity(), + Vector3 { + x: 0.0, + y: 0.0, + z: 0.0 + } + ); + assert_eq!(p.get_mass(), 1.0); + let f = Vector3 { + x: 2.0, + y: 0.0, + z: 0.0, + }; + p.add_force(&f); + p.integrate(1.0).unwrap(); + assert_eq!( + Vector3 { + x: 2.0, + y: 0.0, + z: 0.0 + }, + p.velocity + ); + assert_eq!( + Vector3 { + x: 0.0, + y: 0.0, + z: 0.0 + }, + p.position + ); + p.add_force(&f); + p.integrate(1.0).unwrap(); + assert_eq!( + Vector3 { + x: 4.0, + y: 0.0, + z: 0.0 + }, + p.velocity + ); + assert_eq!( + Vector3 { + x: 2.0, + y: 0.0, + z: 0.0 + }, + p.position + ); + p.integrate(1.0).unwrap(); + assert_eq!( + Vector3 { + x: 4.0, + y: 0.0, + z: 0.0 + }, + p.velocity + ); + assert_eq!( + Vector3 { + x: 6.0, + y: 0.0, + z: 0.0 + }, + p.position + ); + } +} diff --git a/oxide_physics/src/shape.rs b/oxide_physics/src/shape.rs index 64e9477..fc0c149 100644 --- a/oxide_physics/src/shape.rs +++ b/oxide_physics/src/shape.rs @@ -6,14 +6,12 @@ pub trait Shape { fn local_bounding_volume(&self, tv: Vector3) -> AABB; } -#[derive(Debug)] -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] pub struct Ball { radius: f32, } -#[derive(Debug)] -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] // x, y, and z are the half-extent of the cuboid pub struct Cuboid { x: f32, @@ -83,13 +81,31 @@ mod tests { x: 2.0, y: -4.0, z: 6.0, - }).unwrap(); - assert_eq!(Cuboid { - x: 2.0, - y: 4.0, - z: 6.0, - }, cuboid); - assert_eq!(Vector3 { x: -2.0, y: -4.0, z: -6.0}, cuboid.mins()); - assert_eq!(Vector3 { x: 2.0, y: 4.0, z: 6.0}, cuboid.maxs()); + }) + .unwrap(); + assert_eq!( + Cuboid { + x: 2.0, + y: 4.0, + z: 6.0, + }, + cuboid + ); + assert_eq!( + Vector3 { + x: -2.0, + y: -4.0, + z: -6.0 + }, + cuboid.mins() + ); + assert_eq!( + Vector3 { + x: 2.0, + y: 4.0, + z: 6.0 + }, + cuboid.maxs() + ); } } From 1efbae785fcf502594593eb6af881c291376ac7f Mon Sep 17 00:00:00 2001 From: hyunho lee Date: Sat, 8 Jul 2023 20:05:08 +0900 Subject: [PATCH 11/12] fix: particle test typo fixed --- oxide_physics/src/particle.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxide_physics/src/particle.rs b/oxide_physics/src/particle.rs index 61b5635..0a1d0a5 100644 --- a/oxide_physics/src/particle.rs +++ b/oxide_physics/src/particle.rs @@ -227,7 +227,7 @@ mod tests { panic!("{}", msg); } let f = Vector3 { - x: 2.0, + x: 10.0, y: 0.0, z: 0.0, }; From f38b4d69880863b01b19a909e6a941666c06bdef Mon Sep 17 00:00:00 2001 From: hyunho lee Date: Sat, 8 Jul 2023 20:08:12 +0900 Subject: [PATCH 12/12] fix: pfgen functions --- oxide_physics/src/pfgen.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/oxide_physics/src/pfgen.rs b/oxide_physics/src/pfgen.rs index cdde920..28bff4f 100644 --- a/oxide_physics/src/pfgen.rs +++ b/oxide_physics/src/pfgen.rs @@ -35,23 +35,31 @@ pub struct ParticleForceRegistry { } impl ParticleForceRegistry { - pub fn add(&self, particle: DefaultParticleHandle, fg: DefaultForceGeneratorHandle) { - todo!() + pub fn add( + &self, + particle: DefaultParticleHandle, + fg: DefaultForceGeneratorHandle, + ) -> Result { + todo!(); } - pub fn remove(&self, particle: DefaultParticleHandle, fg: DefaultForceGeneratorHandle) { - todo!() + pub fn remove( + &self, + particle: DefaultParticleHandle, + fg: DefaultForceGeneratorHandle, + ) -> Result { + todo!(); } - pub fn clear(&self) { - todo!() + pub fn clear(&self) -> Result { + todo!(); } pub fn update_forces(&self, duration: f32) { // for i in self.registrations.iter_mut() { // i.fg.update_force(i.particle, duration); // } - todo!() + todo!(); } }