diff --git a/rtiow/src/perlin.rs b/rtiow/src/perlin.rs index 9c9d54f..2d19976 100644 --- a/rtiow/src/perlin.rs +++ b/rtiow/src/perlin.rs @@ -3,6 +3,7 @@ use rand::Rng; //use rand::SeedableRng; //use rand::XorShiftRng; +use vec3::dot; use vec3::Vec3; lazy_static! { @@ -11,16 +12,23 @@ lazy_static! { //const SEED: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; pub struct Perlin { - ranfloat: Vec, + ran_vec: Vec, perm_x: Vec, perm_y: Vec, perm_z: Vec, } -fn perlin_generate() -> Vec { +fn perlin_generate() -> Vec { //let mut rng: XorShiftRng = SeedableRng::from_seed(SEED); let mut rng = rand::thread_rng(); - (0..256).map(|_| rng.gen_range::(0., 1.)).collect() + (0..256) + .map(|_| { + Vec3::new( + rng.gen_range::(-1., 1.), + rng.gen_range::(-1., 1.), + rng.gen_range::(-1., 1.), + ).unit_vector() + }).collect() } fn permute(p: &mut Vec, n: usize) { @@ -41,18 +49,25 @@ fn perlin_generate_perm() -> Vec { p } -fn trilinear_interp(c: [[[f32; 2]; 2]; 2], u: f32, v: f32, w: f32) -> f32 { +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 fi = i as f32; - let fj = j as f32; - let fk = k as f32; - accum += (fi * u + (1. - fi) * (1. - u)) - * (fj * v + (1. - fj) * (1. - v)) - * (fk * w + (1. - fk) * (1. - w)) - * c[i][j][k]; + 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); } } } @@ -62,7 +77,7 @@ fn trilinear_interp(c: [[[f32; 2]; 2]; 2], u: f32, v: f32, w: f32) -> f32 { impl Perlin { fn new() -> Perlin { Perlin { - ranfloat: perlin_generate(), + ran_vec: perlin_generate(), perm_x: perlin_generate_perm(), perm_y: perlin_generate_perm(), perm_z: perlin_generate_perm(), @@ -70,29 +85,24 @@ impl Perlin { } pub fn noise(&self, p: Vec3) -> f32 { - let mut u = p.x - p.x.floor(); - let mut v = p.y - p.y.floor(); - let mut w = p.z - p.z.floor(); - - // Hermite cubic to round off interpolation and attempt to address 'mach bands'. - u = u * u * (3. - 2. * u); - v = v * v * (3. - 2. * v); - w = w * w * (3. - 2. * w); + 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: [[[f32; 2]; 2]; 2] = Default::default(); + 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.ranfloat[self.perm_x[(i + di) & 255] - ^ self.perm_y[(j + dj) & 255] - ^ self.perm_z[(k + dk) & 255]] + 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]] } } } - trilinear_interp(c, u, v, w) + perlin_interp(c, u, v, w) } } diff --git a/rtiow/src/texture.rs b/rtiow/src/texture.rs index 385ff6d..6ca0399 100644 --- a/rtiow/src/texture.rs +++ b/rtiow/src/texture.rs @@ -58,6 +58,6 @@ impl NoiseTexture { impl Texture for NoiseTexture { fn value(&self, _u: f32, _v: f32, p: Vec3) -> Vec3 { - Vec3::new(1., 1., 1.) * GENERATOR.noise(self.scale * p) + Vec3::new(1., 1., 1.) * 0.5 * (1. + GENERATOR.noise(self.scale * p)) } }