-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Oxide engine/feat/physics particle #55
Open
Chiefmate
wants to merge
16
commits into
main
Choose a base branch
from
OxideEngine/feat/physics-particle
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 9 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
2a09d60
feat: add particle
Chiefmate 798598b
Merge branch 'main' of https://github.com/OxideEngine/Oxide into Oxid…
be7546c
Work in progress: AABB
Chiefmate 91a06ee
WIP: particle force generator
Chiefmate 4a2aa63
add: ParticleSet, ParticleForceRegistration
Chiefmate 4097a02
add: AABB for ball and cuboid
Chiefmate 6a35f78
style: fmt
Chiefmate f0a77ea
Merge branch 'main' of https://github.com/OxideEngine/Oxide into Oxid…
Chiefmate 6b05121
Merge branch 'main' of https://github.com/OxideEngine/Oxide into Oxid…
44bfeed
refactor: particle and pfgen
215b524
fix: fmt, clippy
Chiefmate 0d6e983
add: AABB tests
Chiefmate a5e9254
add: particle tests
Chiefmate 929079c
Merge branch 'OxideEngine/feat/physics-particle' of https://github.co…
Chiefmate 1efbae7
fix: particle test typo fixed
Chiefmate f38b4d6
fix: pfgen functions
Chiefmate File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
[package] | ||
name = "oxide_physics" | ||
version = "0.0.1" | ||
authors = [ | ||
"Chris Ohk <[email protected]>", | ||
"Changseo Jang <[email protected]>", | ||
"Yongwook Choi <[email protected]>", | ||
"Chaneun Yeo <[email protected]>", | ||
"Seokwon Moon <[email protected]>", | ||
"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" | ||
generational-arena = "0.2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
use crate::collide_broad_phase::{BoundingVolume, HasBoundingVolume}; | ||
use oxide_math::commons::vector3::Vector3; | ||
|
||
pub struct AABB { | ||
pub mins: Vector3, | ||
pub maxs: Vector3, | ||
} | ||
|
||
pub fn aabb<S>(shape: &S, tv: Vector3) -> AABB | ||
where | ||
S: HasBoundingVolume<AABB>, | ||
{ | ||
shape.bounding_volume(tv) | ||
} | ||
|
||
pub fn local_aabb<S>(shape: &S) -> AABB | ||
where | ||
S: HasBoundingVolume<AABB>, | ||
{ | ||
shape.local_bounding_volume() | ||
} | ||
|
||
impl AABB { | ||
pub fn new(mins: Vector3, maxs: Vector3) -> AABB { | ||
AABB { mins, maxs } | ||
} | ||
|
||
pub fn mins(&self) -> Vector3 { | ||
Vector3 { | ||
x: self.mins.x, | ||
y: self.mins.y, | ||
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 | ||
} | ||
|
||
// 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), | ||
}, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
use crate::aabb::AABB; | ||
use crate::collide_broad_phase::HasBoundingVolume; | ||
use crate::shape::Ball; | ||
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<AABB> 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()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
use crate::aabb::AABB; | ||
use crate::collide_broad_phase::HasBoundingVolume; | ||
use crate::shape::Cuboid; | ||
use oxide_math::commons::vector3::Vector3; | ||
|
||
impl HasBoundingVolume<AABB> 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, | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
use oxide_math::commons::vector3::Vector3; | ||
|
||
pub trait BoundingVolume { | ||
// 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<BV> { | ||
// 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, | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
pub mod particle; | ||
pub mod pfgen; | ||
|
||
pub mod shape; | ||
|
||
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
#![allow(dead_code)] | ||
#![allow(unused_variables)] | ||
|
||
use num_traits::pow; | ||
use oxide_math::commons::vector::*; | ||
use oxide_math::commons::vector3::Vector3; | ||
|
||
extern crate generational_arena; | ||
use generational_arena::Arena; | ||
|
||
pub struct Particle { | ||
inverse_mass: f32, | ||
damping: f32, | ||
position: Vector3, | ||
pub velocity: Vector3, | ||
force_accum: Vector3, | ||
acceleration: Vector3, | ||
} | ||
|
||
impl Particle { | ||
// returns integrated velocity | ||
fn integrate(&mut self, duration: f32) -> Result<Vector3, &str> { | ||
// 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, | ||
}); | ||
} | ||
if duration <= 0.0 { | ||
return Err("Cannot integrate with zero duration") | ||
} | ||
|
||
// update linear position | ||
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 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, | ||
}; | ||
|
||
// update linear velocity from the acceleration | ||
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)); | ||
|
||
Particle::clear_accumulator(self); | ||
|
||
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<f32, &str> { | ||
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 | ||
} else { | ||
1.0f32 / self.inverse_mass | ||
} | ||
} | ||
|
||
// 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, | ||
} | ||
} | ||
|
||
pub fn has_finite_mass(&self) -> bool { | ||
self.inverse_mass > 0.0f32 | ||
} | ||
|
||
fn clear_accumulator(&mut self) { | ||
self.force_accum = Vector3 { | ||
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, | ||
}; | ||
} | ||
} | ||
|
||
// The default particle set containing all the particles added to the world | ||
// Uses arena to avoid ABA problem | ||
pub struct DefaultParticleSet { | ||
particles: Arena<Box<Particle>>, | ||
removed: Vec<DefaultParticleHandle>, | ||
} | ||
|
||
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<Box<Particle>> { | ||
let result = self.particles.remove(particle_handle)?; | ||
self.removed.push(particle_handle); | ||
Some(result) | ||
} | ||
} | ||
|
||
impl Default for DefaultParticleSet { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
pub type DefaultParticleHandle = generational_arena::Index; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extern crate
is no longer needed.