From 50510e694610534477220b790cda95bd5b03e83a Mon Sep 17 00:00:00 2001 From: mars Date: Thu, 12 May 2022 13:35:59 -0600 Subject: [PATCH] Particle fountain --- Cargo.toml | 1 + src/main.rs | 145 ++++++++++++++++++++++++++++++++++++++++++------ src/scene.rs | 5 ++ src/viewport.rs | 2 +- 4 files changed, 135 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 064aef0..15c8868 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ multimap = "0.8" notify = "^4" parking_lot = "^0.11" pollster = "0.2" +rand = "^0.8" rayon = "1" slab = "^0.4" smallmap = "^1.0" diff --git a/src/main.rs b/src/main.rs index 8554747..da0bc65 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ use cyborg::storage::mesh::*; use cyborg::viewport::*; use cyborg::Renderer; use legion::*; +use rand::prelude::*; use std::sync::Arc; use winit::{ event::*, @@ -12,6 +13,118 @@ use winit::{ window::WindowBuilder, }; +struct DeltaTime { + pub dt: f32, + last_update: std::time::Instant, +} + +impl Default for DeltaTime { + fn default() -> Self { + DeltaTime { + dt: 0.0, + last_update: std::time::Instant::now(), + } + } +} + +struct SpawnDistributions { + theta: rand::distributions::Uniform, + radius: rand::distributions::Uniform, + up: rand::distributions::Uniform, +} + +impl Default for SpawnDistributions { + fn default() -> Self { + Self { + theta: rand::distributions::Uniform::new(0.0, std::f32::consts::TAU), + radius: rand::distributions::Uniform::new(4.0, 5.0), + up: rand::distributions::Uniform::new(10.0, 15.0), + } + } +} + +struct Particle { + position: glam::Vec3A, + mass: f32, +} + +struct Velocity { + linear: glam::Vec3A, +} + +#[system] +fn update_dt(#[resource] dt: &mut DeltaTime) { + dt.dt = dt.last_update.elapsed().as_secs_f32(); + dt.last_update = std::time::Instant::now(); +} + +#[system(for_each)] +fn apply_gravity(#[resource] dt: &DeltaTime, velocity: &mut Velocity) { + const GRAVITY: f32 = 6.0; + velocity.linear.y -= GRAVITY * dt.dt; +} + +#[system(for_each)] +fn move_particles(#[resource] dt: &DeltaTime, particle: &mut Particle, velocity: &Velocity) { + particle.position += velocity.linear * (dt.dt / particle.mass); + // TODO angular velocity +} + +#[system(for_each)] +fn respawn_particles( + #[resource] distributions: &SpawnDistributions, + particle: &mut Particle, + velocity: &mut Velocity, +) { + if particle.position.y < -10.0 { + particle.position = glam::Vec3A::ZERO; + let rng = &mut rand::thread_rng(); + velocity.linear.y = distributions.up.sample(rng); + + let theta = distributions.theta.sample(rng); + let radius = distributions.radius.sample(rng); + velocity.linear.x = theta.sin() * radius; + velocity.linear.z = theta.cos() * radius; + } +} + +#[system(for_each)] +fn update_transforms(transform: &mut cyborg::scene::Transform, particle: &Particle) { + transform.transform = glam::Mat4::from_translation(particle.position.into()); +} + +#[system(for_each)] +fn update_debug( + draw_list: &mut cyborg::scene::DebugDrawList, + velocity: &Velocity, +) { + draw_list.clear(); + draw_list.indices.extend_from_slice(&[0, 1]); + + let color = [1.0, 1.0, 1.0]; + + draw_list.vertices.push(cyborg::scene::DebugVertex { + position: [0.0, 0.0, 0.0], + color, + }); + + draw_list.vertices.push(cyborg::scene::DebugVertex { + position: velocity.linear.to_array(), + color, + }); +} + +fn build_update_schedule() -> Schedule { + let mut builder = Schedule::builder(); + builder.add_system(update_dt_system()); + builder.add_system(apply_gravity_system()); + builder.add_system(move_particles_system()); + builder.add_system(respawn_particles_system()); + builder.add_system(update_transforms_system()); + builder.add_system(update_debug_system()); + builder.build() +} + fn main() { let event_loop = EventLoop::new(); let window = WindowBuilder::new().build(&event_loop).unwrap(); @@ -20,6 +133,10 @@ fn main() { let mut world = World::new(Default::default()); let mut resources = Resources::default(); + resources.insert::(Default::default()); + resources.insert::(Default::default()); + let mut update_schedule = build_update_schedule(); + let renderer = Renderer::new(viewport.device.clone(), viewport.queue.clone()); resources.insert(renderer); @@ -76,7 +193,7 @@ fn main() { data: bytemuck::cast_slice(&example_vertices).to_vec(), }; - let example_indices: Vec = vec![0, 1, 2, 1, 2, 3, 2, 3, 0, 0, 2, 3]; + let example_indices: Vec = vec![0, 1, 2, 1, 2, 3, 2, 3, 0, 0, 1, 3]; let example_indices = AttrBuffer { id: attributes.index, count: example_indices.len(), @@ -90,21 +207,7 @@ fn main() { drop(mesh_pass); - let example_debug_draw = cyborg::scene::DebugDrawList { - vertices: vec![ - cyborg::scene::DebugVertex { - position: [0.0, 0.0, -0.5], - color: [1.0, 0.0, 0.0], - }, - cyborg::scene::DebugVertex { - position: [0.0, 0.0, 0.5], - color: [0.0, 0.0, 1.0], - }, - ], - indices: vec![0, 1], - }; - - let r = 4; + let r = 6; for x in -r..r { for y in -r..r { for z in -r..r { @@ -115,7 +218,14 @@ fn main() { mesh: example_mesh.clone(), }, cyborg::scene::Transform { transform }, - example_debug_draw.clone(), + cyborg::scene::DebugDrawList::default(), + Particle { + position: translation.into(), + mass: 1.0, + }, + Velocity { + linear: glam::Vec3A::ZERO, + }, )); } } @@ -137,6 +247,7 @@ fn main() { } } Event::MainEventsCleared => { + update_schedule.execute(&mut world, &mut resources); shader_watcher.watch(); flycam.update(); window.request_redraw(); diff --git a/src/scene.rs b/src/scene.rs index b0cec60..1d855b4 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -44,6 +44,11 @@ pub struct DebugDrawList { } impl DebugDrawList { + pub fn clear(&mut self) { + self.vertices.clear(); + self.indices.clear(); + } + pub fn merge(&mut self, other: &Self) { self.vertices.extend_from_slice(&other.vertices); diff --git a/src/viewport.rs b/src/viewport.rs index f6ef180..2a6ef7a 100644 --- a/src/viewport.rs +++ b/src/viewport.rs @@ -61,7 +61,7 @@ impl WinitViewport { format: surface.get_preferred_format(&adapter).unwrap(), width: size.width, height: size.height, - present_mode: wgpu::PresentMode::Fifo, + present_mode: wgpu::PresentMode::Mailbox, }; surface.configure(&device, &config);