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, reflect_color, } } } 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)) } }