use crate::camera::Camera; use crate::hittable::{Hittable, Sphere}; use crate::ray::Ray; use crate::vec3::{Color, Point3, Vec3}; use rand::distributions::{Distribution, Uniform}; use crate::material::{Dielectric, Lambertian, Material, Metal}; mod vec3; mod ray; mod hittable; mod material; mod camera; fn random_scene() -> Vec> { let mut world:Vec> = Vec::new(); let material_ground = Material::Lambertian(Lambertian::new(Color::new(0.5, 0.5, 0.5))); let ground = Sphere { center: Point3::new(0.0, -1000.0, 0.0), radius: 1000.0, material: material_ground }; world.push(Box::new(ground)); let unit_range = Uniform::from(0.0..1.0); let fuzz_range = Uniform::from(0.0..0.5); let mut rng = rand::thread_rng(); let p = Point3::new(4.0, 0.2, 0.0); for a in -1..11 { for b in -11..11 { let choose_material = unit_range.sample(&mut rng); let center = Point3::new( (a as f64) + 0.9*unit_range.sample(&mut rng), 0.2, (b as f64) + 0.9*unit_range.sample(&mut rng)); if (center - p).length() < 0.9 { continue; } let material = match choose_material { _ if choose_material < 0.8 => Material::Lambertian(Lambertian::new( Color::random(0.0, 1.0) * Color::random(0.0, 1.0))), _ if choose_material < 0.95 => Material::Metal(Metal::new( Color::random(0.5, 1.0), fuzz_range.sample(&mut rng))), _ => Material::Dielectric(Dielectric::new(1.5)), }; let sphere = Box::new(Sphere { center, radius: 0.2, material }); world.push(sphere); } } world } fn main() { // Image const ASPECT_RATIO: f64 = 3.0 / 2.0; const IMAGE_WIDTH: i32 = 1200; const IMAGE_HEIGHT: i32 = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as i32; const SAMPLES_PER_PIXEL: i32 = 10; const MAX_DEPTH: i32 = 50; let look_from = Point3::new(13.0, 2.0, 3.0); let look_at = Point3::new(0.0, 0.0, 0.0); let focus_dist = 10.0; // Camera let cam = Camera::new( look_from, look_at, Vec3::new(0.0, 1.0, 0.0), ASPECT_RATIO, 20.0, 0.1, focus_dist); // World let world= random_scene(); println!("P3\n{} {}\n255", IMAGE_WIDTH, IMAGE_HEIGHT); let between = Uniform::from(0.0..1.0); let mut rng = rand::thread_rng(); for j in (0..IMAGE_HEIGHT).rev() { eprint!("\rScanlines remaining: {} ", j); for i in 0..IMAGE_WIDTH { let mut color = Color::default(); for s in 0..SAMPLES_PER_PIXEL { let random_number = between.sample(&mut rng); let u = (i as f64 + random_number) / (IMAGE_WIDTH - 1) as f64; let v = (j as f64 + random_number) / (IMAGE_HEIGHT - 1) as f64; let ray = cam.get_ray(u, v); if i == 200 && (j == 112 || j == 113) { let tt = 0; } color += ray.pixel_color(&world, MAX_DEPTH); } color.write_color(SAMPLES_PER_PIXEL); } } eprintln!("\nDone"); }