summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authoreug-vs <eugene@eug-vs.xyz>2024-12-11 01:02:39 +0100
committereug-vs <eugene@eug-vs.xyz>2024-12-11 01:02:39 +0100
commit376edaead7be57470e74dd2d616f18a2e6bbc0b0 (patch)
tree815cb3919c8e0517e1d4eba2e5411aa797820a59 /src/main.rs
parentac0e2abb003300bd4d414ae9ee5e97c36c0663a2 (diff)
downloadparticle-physics-376edaead7be57470e74dd2d616f18a2e6bbc0b0.tar.gz
feat: solid foundation for particle system
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs169
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);
}
}