ft: 14: random sphere render

This commit is contained in:
2026-04-29 01:54:02 +02:00
parent 2358f8e093
commit 8f244fc6d8

View File

@@ -6,71 +6,18 @@ mod ray;
mod scenes; mod scenes;
mod vec3; mod vec3;
use std::fs;
use std::sync::Arc; use std::sync::Arc;
use crate::camera::Camera;
use crate::objects::materials::dielectric::Dielectric; use crate::objects::materials::dielectric::Dielectric;
use crate::objects::materials::lambertian::{Lambertian, Metal}; use crate::objects::materials::lambertian::{Lambertian, Metal};
use crate::objects::materials::traits::Material;
use crate::objects::sphere::Sphere; use crate::objects::sphere::Sphere;
use crate::objects::traits::Hittable; use crate::objects::traits::Hittable;
use crate::ray::Ray; use crate::ray::Ray;
use crate::scenes::scene::Scene;
use crate::vec3::Vec3; use crate::vec3::Vec3;
use dotenv::dotenv; use dotenv::dotenv;
use log::info;
use pretty_env_logger; use pretty_env_logger;
use rand::RngExt; use rand::RngExt;
use rand::seq::IndexedRandom;
fn random_material() -> Arc<dyn Material> {
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<T: Hittable>(
materials: &Vec<Arc<dyn Material>>,
existing: &Vec<T>,
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 // TODO: implement scene serialization
fn main() { fn main() {
@@ -78,35 +25,94 @@ fn main() {
pretty_env_logger::init(); pretty_env_logger::init();
// TODO: use cli arg for scenefile // TODO: use cli arg for scenefile
let json_file = "./scenes/scene.json"; // 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 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();
let mut scene: Scene = serde_json::from_str(&json_str).unwrap(); // scene.render();
scene.render();
// random spheres code; thought: make this available as cli flag? // random spheres code; thought: make this available as cli flag?
// let mut materials: Vec<Arc<dyn Material>> = vec![Arc::new(Lambertian::rgb(0.1, 0.1, 0.2, 0.8))]; let ground = Lambertian::rgb(0.5, 0.5, 0.5, 1.);
// for i in 0..15 { let mut world: Vec<Arc<dyn Hittable>> = vec![Arc::new(Sphere::xyz(
// info!("Generating {}th material.", i + 1); 0.,
// materials.push(random_material()); -1000.,
// } 0.,
// 1000.,
// let mut world = vec![Sphere::xyz(0., -1000.5, -1., 1000., materials[0].clone())]; Arc::new(ground),
// for i in 0..40 { ))];
// info!("Generating {}th sphere.", i + 1);
// world.push(random_sphere_on_floor( let mut rng = rand::rng();
// &materials, let point = Vec3::new(4., 0.2, 0.);
// &world, for a in -11..11 {
// ((i + 1) as f32).ln() + (15. as f32).log(10.), 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.),
// // let mut c = Camera::new(400, 300); 0.2,
// let mut c = Camera::new(1920, 1080); b as f32 + 0.9 * rng.random_range((0.)..1.),
// c.set_fov(60.); );
// c.set_anti_alias_rate(1);
// c.set_max_depth(10); if (center - point).length() > 0.9 {
// c.set_look_from(Vec3::new(-60., 10., 1.)); if mat < 0.8 {
// c.set_look_at(Vec3::new(0., 0., 0.)); // diffuse
// c.render(&world); 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);
} }