use rand::Rng; use vec3::dot; use vec3::Vec3; pub struct Perlin { ran_vec: Vec, perm_x: Vec, perm_y: Vec, perm_z: Vec, } fn perlin_generate(rng: &mut R) -> Vec where R: Rng, { (0..256) .map(|_| { Vec3::new( rng.gen_range::(-1., 1.), rng.gen_range::(-1., 1.), rng.gen_range::(-1., 1.), ).unit_vector() }).collect() } fn perlin_generate_perm(rng: &mut R) -> Vec where R: Rng, { let mut p: Vec = (0..256).map(|i| i).collect(); rng.shuffle(&mut p); p } fn perlin_interp(c: [[[Vec3; 2]; 2]; 2], u: f32, v: f32, w: f32) -> f32 { // Hermite cubic to round off interpolation and attempt to address 'mach bands'. let uu = u * u * (3. - 2. * u); let vv = v * v * (3. - 2. * v); let ww = w * w * (3. - 2. * w); let mut accum = 0.; for i in 0..2 { for j in 0..2 { for k in 0..2 { let weight_v = Vec3::new(u - i as f32, v - j as f32, w - k as f32); let i = i as f32; let j = j as f32; let k = k as f32; accum += (i * uu + (1. - i) * (1. - uu)) * (j * vv + (1. - j) * (1. - vv)) * (k * ww + (1. - k) * (1. - ww)) * dot(c[i as usize][j as usize][k as usize], weight_v); } } } //info!("u {} v {} accum {}", u, v, accum); accum } impl Perlin { pub fn new(rng: &mut R) -> Perlin where R: Rng, { let p = Perlin { ran_vec: perlin_generate(rng), perm_x: perlin_generate_perm(rng), perm_y: perlin_generate_perm(rng), perm_z: perlin_generate_perm(rng), }; info!( "ran_vec: {}", p.ran_vec .iter() .map(|v| v.to_string()) .collect::>() .join(", ") ); info!( "perm_x: {}", p.perm_x .iter() .map(|v| v.to_string()) .collect::>() .join(", ") ); info!( "perm_y: {}", p.perm_y .iter() .map(|v| v.to_string()) .collect::>() .join(", ") ); info!( "perm_z: {}", p.perm_z .iter() .map(|v| v.to_string()) .collect::>() .join(", ") ); p } pub fn turb(&self, p: Vec3, depth: usize) -> f32 { let mut accum = 0.; let mut temp_p = p; let mut weight = 1.; for _ in 0..depth { accum += weight * self.noise(temp_p); weight *= 0.5; temp_p = temp_p * 0.2; } accum.abs() } pub fn noise(&self, p: V) -> f32 where V: Into, { let p = p.into(); let u = p.x - p.x.floor(); let v = p.y - p.y.floor(); let w = p.z - p.z.floor(); let i = p.x.floor() as usize; let j = p.y.floor() as usize; let k = p.z.floor() as usize; let mut c: [[[Vec3; 2]; 2]; 2] = Default::default(); for di in 0..2 { for dj in 0..2 { for dk in 0..2 { c[di][dj][dk] = self.ran_vec[self.perm_x[(i + di) & 255] ^ self.perm_y[(j + dj) & 255] ^ self.perm_z[(k + dk) & 255]] } } } perlin_interp(c, u, v, w) } }