From 8f244fc6d83ba4bcd1ea0bc787feb1b504e32edd Mon Sep 17 00:00:00 2001 From: djairoh Date: Wed, 29 Apr 2026 01:54:02 +0200 Subject: [PATCH] ft: 14: random sphere render --- src/main.rs | 172 +++++++++++++++++++++++++++------------------------- 1 file changed, 89 insertions(+), 83 deletions(-) diff --git a/src/main.rs b/src/main.rs index bea4234..3433689 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,71 +6,18 @@ mod ray; mod scenes; mod vec3; -use std::fs; use std::sync::Arc; +use crate::camera::Camera; use crate::objects::materials::dielectric::Dielectric; use crate::objects::materials::lambertian::{Lambertian, Metal}; -use crate::objects::materials::traits::Material; use crate::objects::sphere::Sphere; use crate::objects::traits::Hittable; use crate::ray::Ray; -use crate::scenes::scene::Scene; use crate::vec3::Vec3; use dotenv::dotenv; -use log::info; use pretty_env_logger; use rand::RngExt; -use rand::seq::IndexedRandom; - -fn random_material() -> Arc { - let mut rng = rand::rng(); - let col = Vec3::new(rng.random(), rng.random(), rng.random()); - match rng.random_range(0..3) { - 0 => Arc::new(Lambertian::new(col, 1.)), - 1 => Arc::new(Metal::new(col, 1., rng.random())), - 2 => Arc::new(Dielectric::new(rng.random_range(0.3..1.9))), - _ => Arc::new(Metal::new(col, 0., rng.random())), - } -} - -fn random_sphere_on_floor( - materials: &Vec>, - existing: &Vec, - max_size: f32, -) -> Sphere { - let mut rng = rand::rng(); - let r = rng.random_range(0.1..max_size); - let mut sphere = Sphere::xyz( - rng.random_range((-50.)..50.), - rng.random_range(0.1..max_size), - rng.random_range((-50.)..50.), - r, - materials.choose(&mut rng).unwrap().clone(), - ); - - let mut isct = true; - let mut attempts_left = 49; - while isct && attempts_left > 0 { - isct = false; - for h in existing { - if h.inside(&h.closest_on_surface(sphere.center())) { - info!("Generating sphere failed, {} attempts left", attempts_left); - isct = true; - continue; - } - } - if isct { - sphere.set_center(Vec3::new( - rng.random_range(0.5..100.), - r, - rng.random_range(0.5..100.), - )); - } - attempts_left -= 1; - } - sphere -} // TODO: implement scene serialization fn main() { @@ -78,35 +25,94 @@ fn main() { pretty_env_logger::init(); // TODO: use cli arg for scenefile - let json_file = "./scenes/scene.json"; - // let json_file = "./scenes/failsMatBounds.json"; - let json_str = fs::read_to_string(json_file).expect("Reading specified scene file failed!"); - let mut scene: Scene = serde_json::from_str(&json_str).unwrap(); - scene.render(); + // let json_file = "./scenes/scene.json"; + // let json_str = fs::read_to_string(json_file).expect("Reading specified scene file failed!"); + // let mut scene: Scene = serde_json::from_str(&json_str).unwrap(); + // scene.render(); // random spheres code; thought: make this available as cli flag? - // let mut materials: Vec> = vec![Arc::new(Lambertian::rgb(0.1, 0.1, 0.2, 0.8))]; - // for i in 0..15 { - // info!("Generating {}th material.", i + 1); - // materials.push(random_material()); - // } - // - // let mut world = vec![Sphere::xyz(0., -1000.5, -1., 1000., materials[0].clone())]; - // for i in 0..40 { - // info!("Generating {}th sphere.", i + 1); - // world.push(random_sphere_on_floor( - // &materials, - // &world, - // ((i + 1) as f32).ln() + (15. as f32).log(10.), - // )); - // } - // - // // let mut c = Camera::new(400, 300); - // let mut c = Camera::new(1920, 1080); - // c.set_fov(60.); - // c.set_anti_alias_rate(1); - // c.set_max_depth(10); - // c.set_look_from(Vec3::new(-60., 10., 1.)); - // c.set_look_at(Vec3::new(0., 0., 0.)); - // c.render(&world); + let ground = Lambertian::rgb(0.5, 0.5, 0.5, 1.); + let mut world: Vec> = vec![Arc::new(Sphere::xyz( + 0., + -1000., + 0., + 1000., + Arc::new(ground), + ))]; + + let mut rng = rand::rng(); + let point = Vec3::new(4., 0.2, 0.); + for a in -11..11 { + for b in -11..11 { + let mat = rng.random_range((0.)..1.); + let center = Vec3::new( + a as f32 + 0.9 * rng.random_range((0.)..1.), + 0.2, + b as f32 + 0.9 * rng.random_range((0.)..1.), + ); + + if (center - point).length() > 0.9 { + if mat < 0.8 { + // diffuse + world.push(Arc::new(Sphere::new( + center, + 0.2, + Arc::new(Lambertian::new(Vec3::random() * Vec3::random(), 1.)), + ))); + } else if mat < 0.95 { + // metal + world.push(Arc::new(Sphere::new( + center, + 0.2, + Arc::new(Metal::rgb( + rng.random_range(0.5..1.), + rng.random_range(0.5..1.), + rng.random_range(0.5..1.), + 1., + rng.random_range((0.)..0.5), + )), + ))); + } else { + // glass + world.push(Arc::new(Sphere::new( + center, + 0.2, + Arc::new(Dielectric::new(1.5)), + ))); + } + } + } + } + + world.push(Arc::new(Sphere::xyz( + 0., + 1., + 0., + 1., + Arc::new(Dielectric::new(1.5)), + ))); + world.push(Arc::new(Sphere::xyz( + -4., + 1., + 0., + 1., + Arc::new(Lambertian::rgb(0.4, 0.2, 0.1, 1.)), + ))); + world.push(Arc::new(Sphere::xyz( + 4., + 1., + 0., + 1., + Arc::new(Metal::rgb(0.7, 0.6, 0.5, 1., 0.)), + ))); + + let mut c = Camera::new(1920, 1080); + c.set_fov(20.); + c.set_anti_alias_rate(23); + c.set_max_depth(50); + c.set_look_from(Vec3::new(13., 2., 3.)); + c.set_look_at(Vec3::new(0., 0., 0.)); + c.add_defocus_blur(0.6, 10.); + + c.render(&world); }