use std::sync::Arc; use image; use rand; use rand::Rng; use crate::camera::Camera; use crate::constant_medium::ConstantMedium; use crate::cuboid::Cuboid; use crate::hitable::Hit; use crate::hitable_list::HitableList; use crate::kdtree::KDTree; use crate::material::Dielectric; use crate::material::DiffuseLight; use crate::material::Lambertian; use crate::material::Material; use crate::material::Metal; use crate::moving_sphere::MovingSphere; use crate::noise::perlin::Perlin; use crate::noise::NoiseType; use crate::rect::XZRect; use crate::renderer::Opt; use crate::renderer::Scene; use crate::rotate::RotateY; use crate::sphere::Sphere; use crate::texture::ConstantTexture; use crate::texture::ImageTexture; use crate::texture::NoiseTexture; use crate::translate::Translate; use crate::vec3::Vec3; pub fn new(opt: &Opt) -> Scene { let lookfrom = Vec3::new(478., 278., -600.); let lookat = Vec3::new(278., 278., 0.); let dist_to_focus = 10.; let aperture = 0.0; let t_min = 0.; let t_max = 1.; let camera = Camera::new( lookfrom, lookat, Vec3::new(0., 1., 0.), 40., opt.width as f32 / opt.height as f32, aperture, dist_to_focus, t_min, t_max, ); let nb = 20; let rng = &mut rand::thread_rng(); let mut boxlist: Vec> = Vec::with_capacity(10000); let mut list: Vec> = Vec::new(); let white: Arc = Arc::new(Lambertian::new(ConstantTexture::new([0.73, 0.73, 0.73]))); let ground: Arc = Arc::new(Lambertian::new(ConstantTexture::new([0.48, 0.83, 0.53]))); for i in 0..nb { for j in 0..nb { let w = 100.; let x0 = -1000. + i as f32 * w; let z0 = -1000. + j as f32 * w; let y0 = 0.; let x1 = x0 + w; let y1 = 100. * (rng.gen_range::(0., 1.) + 0.01); let z1 = z0 + w; boxlist.push(Box::new(Cuboid::new( Vec3::new(x0, y0, z0), Vec3::new(x1, y1, z1), Arc::clone(&ground), ))); } } list.push(Box::new(KDTree::new(boxlist, t_min, t_max))); let light = DiffuseLight::new(ConstantTexture::new([7., 7., 7.])); // Light in ceiling list.push(Box::new(XZRect::new(123., 423., 147., 412., 554., light))); let center = Vec3::new(400., 400., 200.); // Moving brownish ball list.push(Box::new(MovingSphere::new( center, center + Vec3::new(30., 0., 0.), 50., t_min, t_max, Lambertian::new(ConstantTexture::new([0.7, 0.3, 0.1])), ))); // Glass ball, lower-left corner list.push(Box::new(Sphere::new( [260., 150., 45.], 50., Dielectric::new(1.5), ))); // Metal ball lower-right corner list.push(Box::new(Sphere::new( [0., 150., 145.], 50., Metal::new([0.8, 0.8, 0.9], 10.0), ))); // Blue smokey glass ball lower-left let boundary: Arc = Arc::new(Sphere::new([360., 150., 145.], 70., Dielectric::new(1.5))); list.push(Box::new(Arc::clone(&boundary))); list.push(Box::new(ConstantMedium::new( Arc::clone(&boundary), 0.2, ConstantTexture::new([0.2, 0.4, 0.9]), ))); // General white mist over whole scene let boundary: Arc = Arc::new(Sphere::new([0., 0., 0.], 5000., Dielectric::new(1.5))); list.push(Box::new(Arc::clone(&boundary))); list.push(Box::new(ConstantMedium::new( Arc::clone(&boundary), 0.0001, ConstantTexture::new([1.0, 1.0, 1.0]), ))); // Earth sphere let world_image_bytes = include_bytes!("../../images/world.jpg"); let world = ImageTexture::new(image::load_from_memory(world_image_bytes).unwrap().to_rgb()); list.push(Box::new(Sphere::new( Vec3::new(400., 200., 400.), 100., Lambertian::new(world), ))); // Perlin noise sphere let noise_source = Perlin::new(rng); let noise_type = NoiseType::Marble { period: Vec3::new(0., 1., 0.), power: 4., size: 32, scale: 0.5, }; let pertext = NoiseTexture::new(noise_source, noise_type); list.push(Box::new(Sphere::new( [220., 280., 300.], 80., Lambertian::new(pertext), ))); // White 'cube' made of 1000 spheres let ns = 1000; let mut boxlist: Vec> = Vec::with_capacity(1000); for _ in 0..ns { boxlist.push(Box::new(Sphere::new( [ 165. * rng.gen_range::(0., 1.), 165. * rng.gen_range::(0., 1.), 165. * rng.gen_range::(0., 1.), ], 10., Arc::clone(&white), ))); } list.push(Box::new(Translate::new( RotateY::new(KDTree::new(boxlist, t_min, t_max), 15.), [-100., 270., 395.], ))); Scene { camera, world: Box::new(HitableList::new(list)), subsamples: opt.subsamples, num_threads: opt.num_threads, width: opt.width, height: opt.height, global_illumination: false, env_map: None, } }