diff options
author | eug-vs <eugene@eug-vs.xyz> | 2024-12-11 01:02:39 +0100 |
---|---|---|
committer | eug-vs <eugene@eug-vs.xyz> | 2024-12-11 01:02:39 +0100 |
commit | 376edaead7be57470e74dd2d616f18a2e6bbc0b0 (patch) | |
tree | 815cb3919c8e0517e1d4eba2e5411aa797820a59 /src/main.rs | |
parent | ac0e2abb003300bd4d414ae9ee5e97c36c0663a2 (diff) | |
download | particle-physics-376edaead7be57470e74dd2d616f18a2e6bbc0b0.tar.gz |
feat: solid foundation for particle system
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 169 |
1 files changed, 15 insertions, 154 deletions
diff --git a/src/main.rs b/src/main.rs index ab2e15f..fcf19c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,167 +1,28 @@ -use std::io::Write; -use std::{fs::File, path::PathBuf}; -use cgmath::{Angle, ElementWise, InnerSpace, Matrix3, MetricSpace, Rad, Vector3, Zero}; - -type Vector = Vector3<f32>; - -#[derive(Debug, Clone, Copy)] -struct Particle { - position: Vector, - position_old: Vector, - // velocity: Vector, - acceleration: Vector, - mass: f32, - fixed: bool, -} - -impl Particle { - pub fn new(position: Vector, mass: f32, fixed: bool) -> Self { - Self { - position, - position_old: position, - acceleration: Vector::zero(), - mass, - fixed, - } - - } - - fn apply_force(&mut self, force: Vector) { - self.acceleration += force / self.mass; - } - - fn tick(&mut self, dt: f32) { - if !self.fixed { - // Verlet method - let velocity = self.position - self.position_old; - self.position_old = self.position; - self.position += velocity + self.acceleration * dt * dt; - } - - self.acceleration = Vector::zero(); - } -} - -#[derive(Debug, Clone, Copy)] -struct Spring { - rest_length: f32, - stiffness: f32, - particle_ids: [usize; 2], -} - -#[derive(Debug, Clone)] -struct Simulation { - particles: Vec<Particle>, - springs: Vec<Spring>, -} - -impl Simulation { - fn tick(&mut self, dt: f32) { - for spring in self.springs.iter() { - let [a, b] = spring.particle_ids; - let dist_vec = self.particles[b].position - self.particles[a].position; - let force_magnitude = spring.stiffness * (dist_vec.magnitude() - spring.rest_length); - let normalized = dist_vec.normalize(); - - self.particles[a].apply_force(normalized.mul_element_wise(force_magnitude)); - self.particles[b].apply_force(normalized.mul_element_wise(force_magnitude * -1.0)); - } - for p in &mut self.particles { - p.tick(dt); - } - } -} - - -struct PPM { - prefix: PathBuf, - width: usize, - height: usize, - // pixels_per_unit: usize, -} - -impl PPM { - fn render_particles(&self, particles: &Vec<Particle>) -> String { - let mut s = format!("P3\n{} {}\n255\n", self.width, self.height); - let white = "255 255 255 "; - let black = "0 0 0 "; - - for pixel_row in 0..self.height { - for pixel_col in 0..self.width { - let point = Vector::new(pixel_col as f32, 0.0, (pixel_row as f32) * -1.0) + Vector::new(self.width as f32 / -2.0, 0.0, self.height as f32 / 2.0); - let color = match particles.iter().any(|p| p.position.distance(point) <= p.mass / 2.0) { - true => black, - false => white, - }; - s += color; - } - } - s - } - - fn save_frame(&self, particles: &Vec<Particle>, time: f32) { - let file_name = format!("frame-{:08.3}", time); - let path = self.prefix.join(file_name); - let mut file = File::create(path).unwrap(); - let data = self.render_particles(particles); - file.write(data.as_bytes()).unwrap(); - } -} +use particle_system::{Particle, ParticleSystem, Point, Vector}; +mod particle_system; fn main() { - let rotation_matrix = Matrix3::from_axis_angle(Vector::unit_y(), -Rad::full_turn() / 12.0); - - let mut simulation = Simulation { - particles: vec![ - Particle::new(Vector::zero(), 5.0, true), - Particle::new(rotation_matrix * Vector::unit_x() * 40.0, 30.0, false), - Particle::new(rotation_matrix * Vector::unit_x() * 40.0 + rotation_matrix * rotation_matrix * Vector::unit_x() * 50.0, 15.0, false) - ], - springs: vec![ - Spring { - particle_ids: [0, 1], - rest_length: 40.0, - stiffness: 400.0, - }, - Spring { - particle_ids: [1, 2], - rest_length: 50.0, - stiffness: 5.0, - }, - ], + let dt = 0.01; + let mut system = ParticleSystem { + particles: vec![Particle::new(Point::origin(), 1.0)], + t: 0.0, }; + let gravity = -9.8 * Vector::y(); - let ppm = PPM { - prefix: PathBuf::from("./out"), - width: 150, - height: 800, - }; - - let gravity = Vector::new(0.0, 0.0, -9.8); - - let time_step = 0.01; - let mut tick = 1; - let mut time = 0.0; - while time < 130.0 { - { - let p = &mut simulation.particles[0]; - p.apply_force(gravity * -p.mass); - } - let mut all_particles = Vec::new(); - for p in &mut simulation.particles { - p.apply_force(gravity * p.mass); + for i in 0..3 { + println!("Iteration #{i}"); + for particle in &mut system.particles { + particle.reset_force(); } - simulation.tick(time_step); - all_particles.append(&mut simulation.particles.clone()); - if tick % 10 == 0 { - ppm.save_frame(&all_particles, time); + for particle in &mut system.particles { + particle.apply_force(gravity); } + system.euler_step(dt); - time += time_step; - tick +=1; + println!("{:?}", system); } } |