diff --git a/src/main.rs b/src/main.rs index 9a08765..ec7db50 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ use rand::distributions::{Distribution, Uniform}; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use crate::material::{Dielectric, DiffuseLight, Lambertian, Material, Metal}; use crate::aabb::Aabb; +use crate::bvh::BVH; use crate::constant_medium::ConstantMedium; use crate::cuboid::Cuboid; use crate::image_texture::ImageTexture; @@ -42,7 +43,7 @@ mod isotropic; // Image const DEFAULT_ASPECT_RATIO: f64 = 3.0 / 2.0; -const IMAGE_WIDTH: usize = 600; +const IMAGE_WIDTH: usize = 800; const SAMPLES_PER_PIXEL: i32 = 200; const MAX_DEPTH: i32 = 50; @@ -603,9 +604,178 @@ fn random_scene() -> Scene { } } +fn next_week_final() -> Scene { + let ground = Arc::new( + Material::Lambertian(Lambertian::from(Color::new(0.48, 0.84, 0.53)))); + let boxes_per_side = 20; + let mut rng = rand::thread_rng(); + let box_range = Uniform::from(1.0..101.0); + let mut boxes1: HittableList = Vec::with_capacity(boxes_per_side*boxes_per_side); + for i in 0..boxes_per_side { + for j in 0..boxes_per_side { + let w = 100.0; + let x0 = -1000.0 + (i as f64)*w; + let z0 = -1000.0 + (j as f64)*w; + let y0 = 0.0; + let x1 = x0 + w; + let y1 = box_range.sample(&mut rng); + let z1 = z0 + w; + boxes1.push(Arc::new(Cuboid::new( + Vec3::new(x0, y0, z0), + Vec3::new(x1, y1, z1), + ground.clone() + ))); + } + } + + let mut world: HittableList = Vec::new(); + world.push(Arc::new(BVH::new(boxes1, 0.0, 1.0))); + + let light = Arc::new( + Material::DiffuseLight(DiffuseLight::from(Color::new(7.0, 7.0, 7.0)))); + world.push(Arc::new(Rect2D::new( + Plane::XZ, + 123.0, + 423.0, + 147.0, + 412.0, + 554.0, + light + ))); + + let moving_sphere_material = Arc::new( + Material::Lambertian(Lambertian::from(Color::new(0.7, 0.3, 0.1)))); + let center1 = Point3::new(400.0, 400.0, 200.0); + world.push(Arc::new(MovableSphere::new( + center1, + center1 + Vec3::new(30.0, 0.0, 0.0), + 50.0, + moving_sphere_material, + 0.0, + 1.0 + ))); + + let glass = Arc::new(Material::Dielectric(Dielectric::new(1.5))); + world.push(Arc::new(Sphere::new( + Point3::new(260.0, 150.0, 45.0), + 50.0, + glass.clone() + ))); + world.push(Arc::new(Sphere::new( + Point3::new(0.0, 150.0, 145.0), + 50.0, + Arc::new( + Material::Metal(Metal::new(Color::new(0.8, 0.8, 0.9), 1.0))) + ))); + let boundary = Sphere::new( + Point3::new(360.0, 150.0, 145.0), + 70.0, + glass.clone() + ); + let boundary_clone = Sphere::new( + Point3::new(360.0, 150.0, 145.0), + 70.0, + glass.clone() + ); + world.push(Arc::new(boundary_clone)); + world.push(Arc::new( + ConstantMedium::colored( + boundary, + Color::new(0.2, 0.4, 0.9), + 0.2))); + let boundary = Sphere::new( + Point3::new(0.0, 0.0, 0.0), + 5000.0, + glass.clone() + ); + world.push(Arc::new( + ConstantMedium::colored( + boundary, + Color::new(1.0, 1.0, 1.0), + 0.0001))); + + let earth_material = Arc::new(Material::Lambertian( + Lambertian::textured( + Arc::new(ImageTexture::new("textures/earthmap.jpg"))))); + world.push(Arc::new(Sphere::new( + Point3::new(400.0, 200.0, 400.0), + 100.0, + earth_material + ))); + + let pertext = Arc::new(Material::Lambertian(Lambertian::textured( + Arc::new(NoiseTexture { + noise: Perlin::new(), + scale: 0.1 + })))); + world.push(Arc::new(Sphere::new( + Point3::new(220.0, 280.0, 300.0), + 100.0, + pertext + ))); + + let ns = 1000; + let mut boxes2: HittableList = Vec::with_capacity(ns); + let white = Arc::new(Material::Lambertian( + Lambertian::from(Color::new(0.73, 0.73, 0.73)))); +/* + for _i in 0..ns { + world.push(Arc::new( + Translate::new( + Sphere::new( + Point3::random(0.0, 165.0), + 10.0, + white.clone() + ),Vec3::new(-100.0, 270.0, 395.0)) + )); + } +*/ + + for _i in 0..ns { + boxes2.push(Arc::new( + Sphere::new( + Point3::random(0.0, 165.0), + 10.0, + white.clone() + ) + )); + } + + + + let boxes2_bvh = BVH::new(boxes2, 0.0, 1.0); + //let rotated_bvh = RotateY::new(boxes2_bvh, 0.0); + //let rotated_bvh = RotateY::new(boxes2_bvh, 15.0); + //let translated_bvh = Translate::new(rotated_bvh, Vec3::new(-100.0, 270.0, 395.0)); + let translated_bvh = Translate::new(boxes2_bvh, Vec3::new(-100.0, 270.0, 395.0)); + world.push(Arc::new(translated_bvh)); + + let look_from = Point3::new(478.0, 278.0, -600.0); + let look_at = Point3::new(278.0, 278.0, 0.0); + let focus_dist = 2.0; + + let cam = Camera::new( + look_from, + look_at, + Vec3::new(0.0, 1.0, 0.0), + 1.0, + 40.0, + 0.0, + focus_dist, + 0.0, + 1.0); + + Scene { + world, + cam, + background: Color::default() + } +} + fn main() { + rayon::ThreadPoolBuilder::new().num_threads(3).build_global().unwrap(); // Enable, to reduce load // World - let scene: u8 = 6; + let scene: u8 = 7; let scene_setup = match scene { 0 => two_spheres(), 1 => two_perlin_spheres(), @@ -614,6 +784,7 @@ fn main() { 4 => simple_light(), 5 => cornell_box(), 6 => cornell_box_smoke(), + 7 => next_week_final(), _ => random_scene(), }; @@ -623,7 +794,7 @@ fn main() { let image_height: usize = (IMAGE_WIDTH as f64 / scene_setup.cam.aspect_ratio()) as usize; let mut pixels = vec![0; IMAGE_WIDTH * image_height * 3]; let bands: Vec<(usize, &mut [u8])> = pixels.chunks_mut(3).enumerate().collect(); - //rayon::ThreadPoolBuilder::new().num_threads(3).build_global().unwrap(); // Enable, to reduce load + let count = Mutex::new(0); bands.into_par_iter().for_each(|(i, pixel)| { let row = image_height - (i / IMAGE_WIDTH) - 1; diff --git a/src/translate.rs b/src/translate.rs index 96c174c..61896ed 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -18,31 +18,17 @@ impl Hittable for Translate { ray.origin() - self.offset, ray.direction(), ray.time()); - match &self.hittable.hit(&moved_ray, t_min, t_max) { - Some(hit_record) => { - let mut hr = HitRecord { - point: hit_record.point + self.offset, - material: hit_record.material, - front_face: hit_record.front_face, // Maybe need to calc normal and front_face again? - normal: hit_record.normal, - t: hit_record.t, - u: hit_record.u, - v: hit_record.v - }; - hr.normalized(ray); - Some(hr) - } - _ => None - } + self.hittable.hit(&moved_ray, t_min, t_max).map(|mut hr| { + hr.point += self.offset; + hr + }) } fn bounding_box(&self, time0: f64, time1: f64) -> Option { - match &self.hittable.bounding_box(time0, time1) { - Some(bounding_box) => Some(Aabb { - minimum: bounding_box.minimum + self.offset, - maximum: bounding_box.maximum + self.offset, - }), - _ => None - } + self.hittable.bounding_box(time0, time1).map(|mut b| { + b.min += self.offset; + b.max += self.offset; + b + }) } }