ft (wip): random scene generation

This commit is contained in:
2026-04-25 05:20:15 +02:00
parent 5f2c419af5
commit ef8da70436
4 changed files with 113 additions and 23 deletions

View File

@@ -1,6 +1,6 @@
use std::f32::consts::PI; use std::f32::consts::PI;
use log::{info, warn}; use log::info;
use crate::{ use crate::{
objects::{hit::Hit, traits::Hittable}, objects::{hit::Hit, traits::Hittable},
@@ -129,7 +129,6 @@ impl Camera {
if self.dirty { if self.dirty {
self.init() self.init()
} }
warn!("{}", format!("{self:#?}"));
let mut imgbuf = image::ImageBuffer::new(self.image_width, self.image_height); let mut imgbuf = image::ImageBuffer::new(self.image_width, self.image_height);

View File

@@ -10,39 +10,109 @@ use std::sync::Arc;
use crate::camera::Camera; 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::ray::Ray; use crate::ray::Ray;
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::seq::IndexedRandom;
use rand::RngExt;
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.),
r,
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
}
fn main() { fn main() {
dotenv().ok(); dotenv().ok();
pretty_env_logger::init(); pretty_env_logger::init();
// setup objects // setup objects
let blue = Arc::new(Metal::rgb(0.2, 0.4, 0.8, 1., 0.1)); // let blue = Arc::new(Metal::rgb(0.2, 0.4, 0.8, 1., 0.1));
let metal = Arc::new(Metal::rgb(0.7, 0.4, 0.2, 1., 0.1)); // let metal = Arc::new(Metal::rgb(0.7, 0.4, 0.2, 1., 0.1));
let ground = Arc::new(Lambertian::rgb(0.8, 0.8, 0., 1.0)); // let ground = Arc::new(Lambertian::rgb(0.8, 0.8, 0., 1.0));
let center = Arc::new(Lambertian::rgb(0.1, 0.2, 0.5, 1.)); // let center = Arc::new(Lambertian::rgb(0.1, 0.2, 0.5, 1.));
let left = Arc::new(Dielectric::new(1.5)); // let left = Arc::new(Dielectric::new(1.5));
let bubble = Arc::new(Dielectric::new(1. / 1.5)); // let bubble = Arc::new(Dielectric::new(1. / 1.5));
let right = Arc::new(Metal::rgb(0.8, 0.6, 0.2, 1., 1.0)); // let right = Arc::new(Metal::rgb(0.8, 0.6, 0.2, 1., 1.0));
//
// let mut world = vec![Sphere::xyz(0., 0.5, -0.8, 0.1, metal.clone())];
// world.push(Sphere::xyz(0., -100.5, -1., 100., ground.clone()));
// world.push(Sphere::xyz(0., 0., -1.2, 0.5, center.clone()));
// world.push(Sphere::xyz(-1., 0., -1.0, 0.5, left.clone()));
// world.push(Sphere::xyz(-1., 0., -1.0, 0.4, bubble.clone()));
// world.push(Sphere::xyz(1., 0., -1.0, 0.5, right.clone()));
// world.push(Sphere::xyz(0., 0.7, -0.4, 0.2, blue.clone()));
let mut world = vec![Sphere::xyz(0., 0.5, -0.8, 0.1, metal.clone())]; let mut materials: Vec<Arc<dyn Material>> = vec![Arc::new(Lambertian::rgb(0.1, 0.2, 0.6, 1.))];
world.push(Sphere::xyz(0., -100.5, -1., 100., ground.clone())); for i in 0..15 {
world.push(Sphere::xyz(0., 0., -1.2, 0.5, center.clone())); info!("Generating {}th material.", i + 1);
world.push(Sphere::xyz(-1., 0., -1.0, 0.5, left.clone())); materials.push(random_material());
world.push(Sphere::xyz(-1., 0., -1.0, 0.4, bubble.clone())); }
world.push(Sphere::xyz(1., 0., -1.0, 0.5, right.clone()));
world.push(Sphere::xyz(0., 0.7, -0.4, 0.2, blue.clone()));
let mut c = Camera::new(400, 300); let mut world = vec![Sphere::xyz(0., -1000.5, -1., 1000., materials[0].clone())];
// let mut c = Camera::new(1920, 1080); for i in 0..40 {
c.set_fov(20.); info!("Generating {}th sphere.", i + 1);
c.set_anti_alias_rate(2); world.push(random_sphere_on_floor(
c.set_max_depth(90); &materials,
c.set_look_from(Vec3::new(-2., 2., 1.)); &world,
c.set_look_at(Vec3::new(0., 0., -1.)); (i + 1) as f32 / 3.,
));
}
// let mut c = Camera::new(400, 300);
let mut c = Camera::new(1920, 1080);
c.set_fov(90.);
c.set_anti_alias_rate(6);
c.set_max_depth(100);
c.set_look_from(Vec3::new(-60., 10., 1.));
c.set_look_at(Vec3::new(0., 0., 0.));
c.render(&world); c.render(&world);
} }

View File

@@ -29,6 +29,16 @@ impl Sphere {
material: mat, material: mat,
} }
} }
pub fn center(&self) -> &Vec3 {
&self.center
}
pub fn set_center(&mut self, center: Vec3) {
if self.center != center {
self.center = center;
}
}
} }
impl Hittable for Sphere { impl Hittable for Sphere {
@@ -60,4 +70,12 @@ impl Hittable for Sphere {
fn normal_at(&self, p: &Vec3) -> Vec3 { fn normal_at(&self, p: &Vec3) -> Vec3 {
(*p - self.center).get_unit() (*p - self.center).get_unit()
} }
fn inside(&self, p: &Vec3) -> bool {
(*p - self.center).length() < self.radius
}
fn closest_on_surface(&self, p: &Vec3) -> Vec3 {
self.normal_at(p) * self.radius
}
} }

View File

@@ -5,4 +5,7 @@ use crate::Vec3;
pub trait Hittable { pub trait Hittable {
fn hit(&self, r: &Ray) -> Option<Hit>; fn hit(&self, r: &Ray) -> Option<Hit>;
fn normal_at(&self, p: &Vec3) -> Vec3; fn normal_at(&self, p: &Vec3) -> Vec3;
// fn intersect<H: Hittable>(&self, o: &H) -> bool;
fn inside(&self, p: &Vec3) -> bool;
fn closest_on_surface(&self, p: &Vec3) -> Vec3;
} }