diff --git a/Cargo.lock b/Cargo.lock index 9377e98..27e123d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -174,6 +174,12 @@ dependencies = [ "syn", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.9.0" @@ -625,6 +631,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + [[package]] name = "libredox" version = "0.1.3" @@ -763,6 +775,16 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + [[package]] name = "num_enum" version = "0.7.3" @@ -1108,6 +1130,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "presser" version = "0.3.1" @@ -1156,6 +1187,55 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "rand_pcg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" +dependencies = [ + "rand_core", +] + [[package]] name = "range-alloc" version = "0.1.3" @@ -1175,6 +1255,9 @@ dependencies = [ "bytemuck", "glam", "pollster", + "rand", + "rand_distr", + "rand_pcg", "wgpu", "winit", ] @@ -2221,6 +2304,7 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] diff --git a/Cargo.toml b/Cargo.toml index 8a5188a..0aef428 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,5 +7,8 @@ edition = "2021" bytemuck = { version = "1.21.0", features = ["derive"] } glam = { version = "0.29.2", features = ["bytemuck"] } pollster = "0.4.0" +rand = "0.8.5" +rand_distr = { version = "0.4.3", features = ["std_math"] } +rand_pcg = "0.3.1" wgpu = "23.0.1" winit = "0.30.6" diff --git a/src/anim.rs b/src/anim.rs new file mode 100644 index 0000000..94f8840 --- /dev/null +++ b/src/anim.rs @@ -0,0 +1,77 @@ +use glam::{vec3, Vec3}; +use rand_distr::{Distribution, LogNormal, Uniform}; + +pub struct SphereParams { + pub radius: f32, + pub color: Vec3, + pub alpha: f32, + pub origin: Vec3, + pub amplitudes: Vec3, + pub frequencies: Vec3, + pub phases: Vec3, +} + +pub struct SphereParamsDistribution { + pub drad: Uniform, + pub dpos: Uniform, + pub dcol: Uniform, + pub demit: LogNormal, + pub dampl: Uniform, + pub dfreq: Uniform, + pub dphase: Uniform, +} + +impl Default for SphereParamsDistribution { + fn default() -> Self { + Self { + drad: Uniform::new(0.01, 0.10), + dpos: Uniform::new(-1.0, 1.0), + dcol: Uniform::new(0.0, 1.0), + demit: LogNormal::new(-0.8, 2.0).unwrap(), + dampl: Uniform::new(0.3, 0.8), + dfreq: Uniform::new(0.2, 1.5), + dphase: Uniform::new(0., 2. * std::f32::consts::PI), + } + } +} + +impl SphereParamsDistribution { + pub fn make_params(&self, rgen: &mut impl rand::Rng) -> SphereParams { + SphereParams { + origin: self.dpos.sample3(rgen), + radius: self.drad.sample(rgen), + color: self.dcol.sample3(rgen).normalize(), + alpha: self.demit.sample(rgen), + amplitudes: self.dampl.sample3(rgen), + frequencies: self.dfreq.sample3(rgen), + phases: self.dphase.sample3(rgen), + } + } +} + +impl SphereParams { + pub fn to_sphere(&self, time: f32) -> crate::Sphere { + let center = self.origin + self.amplitudes * (self.frequencies * time + self.phases).map(|x| x.sin()); + let radius = self.radius; + let emit_color = self.alpha * self.color; + let reflect_color = 0.6 * self.color + Vec3::splat(0.2); + crate::Sphere { + center, + radius, + emit_color, + pad1: 0.0, + reflect_color, + pad2: 0.0, + } + } +} + +trait VecDistribution { + fn sample3(&self, rng: &mut R) -> Vec3; +} + +impl> VecDistribution for T { + fn sample3(&self, rng: &mut R) -> Vec3 { + vec3(rng.sample(self), rng.sample(self), rng.sample(self)) + } +} diff --git a/src/main.rs b/src/main.rs index d4e6d7e..d0846d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,18 @@ use std::error::Error; use glam::{vec2, vec3}; -use trace::{Sphere, Tracer, TracerData, Vertex}; +use trace::{Tracer, TracerData, Vertex}; use winit::{ event::{Event, WindowEvent}, event_loop::EventLoop, window::{Window, WindowAttributes}, }; +mod anim; mod trace; +pub use trace::Sphere; + fn make_viewport(w: u32, h: u32) -> [Vertex; 4] { let w = w as f32; let h = h as f32; @@ -30,6 +33,8 @@ fn make_viewport(w: u32, h: u32) -> [Vertex; 4] { }) } +const N_SPHERES: u32 = 42; + fn main() { let event_loop = EventLoop::new().unwrap(); @@ -46,32 +51,16 @@ fn main() { trace::Params { max_reflections: 3, min_strength: 0.1, - sphere_count: 2, + sphere_count: N_SPHERES, }, ); + let sphere_params: Vec<_> = { + let mut rng = rand_pcg::Pcg32::new(42, 0); + let distr = anim::SphereParamsDistribution::default(); + (0..N_SPHERES).map(|_| distr.make_params(&mut rng)).collect() + }; - let mut data = TracerData::new( - &device, - &tracer, - &[ - Sphere { - center: vec3(0.0, 0.0, 0.0), - radius: 0.5, - emit_color: vec3(0.0, 0.0, 0.5), - reflect_color: vec3(1.0, 0.5, 0.0), - pad1: 0., - pad2: 0., - }, - Sphere { - center: vec3(-2.0, 0.0, 2.0), - radius: 0.5, - emit_color: vec3(0.5, 0.5, 0.5), - reflect_color: vec3(0.0, 0.5, 0.0), - pad1: 0., - pad2: 0., - }, - ], - ); + let mut time = 0.0; let mut surface_configured = false; #[allow(deprecated)] @@ -101,6 +90,10 @@ fn main() { if !surface_configured { return; } + time += 1. / 60.; + let spheres: Vec<_> = sphere_params.iter().map(|p| p.to_sphere(time)).collect(); + let data = TracerData::new(&device, &tracer, &spheres); + let output = surface.get_current_texture().unwrap(); let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default()); let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); @@ -139,7 +132,7 @@ async fn init_gpu(wnd: &Window) -> Result<(wgpu::Device, wgpu::Queue, wgpu::Surf let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), - compatible_surface: None, + compatible_surface: Some(&surface), force_fallback_adapter: false, }) .await