From 899f81eed6c221dce22333ad03704b12d7634a54 Mon Sep 17 00:00:00 2001 From: Sakarias Johansson Date: Sun, 8 Jan 2023 17:51:44 +0100 Subject: =?UTF-8?q?=F0=9F=8C=8D=20Add=20Geometry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Created a trait for all geometry that has to implement a hit function. Depending on if the ray hits or not it returns an option with the color. - Add support for multiple samples per pixel Current issues: - Using cooperative multitasking which isn't that helpful in this situation since it's like running without async but without overhead. Should switch to rayon. - All data gets copied once per job. Will decide later what to do (copy or put locks and share data between jobs). --- racer-tracer/src/main.rs | 76 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 18 deletions(-) (limited to 'racer-tracer/src/main.rs') diff --git a/racer-tracer/src/main.rs b/racer-tracer/src/main.rs index 1951da5..9d45762 100644 --- a/racer-tracer/src/main.rs +++ b/racer-tracer/src/main.rs @@ -1,51 +1,86 @@ #[macro_use] mod error; mod camera; +mod geometry; mod image; mod ray; +mod scene; mod util; mod vec3; -use crate::vec3::Vec3; use std::vec::Vec; use futures::{select, stream::FuturesUnordered, stream::StreamExt}; +use geometry::Hittable; use minifb::{Key, Window, WindowOptions}; -fn ray_color(ray: &ray::Ray) -> Vec3 { - let unit_direction = vec3::unit_vector(ray.direction()); +use crate::camera::Camera; +use crate::geometry::sphere::Sphere; +use crate::image::Image; +use crate::ray::Ray; +use crate::scene::Scene; +use crate::util::random_double; +use crate::vec3::Vec3; + +fn ray_color(scene: &Scene, ray: &Ray) -> Vec3 { + if let Some(hit_record) = scene.hit(ray, 0.0, std::f64::INFINITY) { + //return hit_record.color; + return 0.5 * (hit_record.normal + Vec3::new(1.0, 1.0, 1.0)); + } + + // Sky + let unit_direction = ray.direction().unit_vector(); let t = 0.5 * (unit_direction.y() + 1.0); (1.0 - t) * Vec3::new(1.0, 1.0, 1.0) + t * Vec3::new(0.5, 0.7, 1.0) } +// TODO: Rustify async fn raytrace( - camera: camera::Camera, - image: image::Image, + scene: Scene, + camera: Camera, + image: Image, row: usize, ) -> Result<(usize, Vec), error::TracerError> { let mut buffer: Vec = vec![0; image.width as usize]; + let mut colors: Vec = vec![Vec3::default(); image.width as usize]; for i in 0..buffer.len() { - let u: f64 = i as f64 / (image.width - 1) as f64; - let v: f64 = row as f64 / (image.height - 1) as f64; - let ray = ray::Ray::new( - camera.origin, - camera.lower_left_corner + u * camera.horizontal + v * camera.vertical - camera.origin, - ); - let col = ray_color(&ray); - buffer[i] = col.as_color(); + for _ in 0..image.samples_per_pixel { + let u: f64 = (i as f64 + random_double()) / (image.width - 1) as f64; + let v: f64 = (row as f64 + random_double()) / (image.height - 1) as f64; + colors[i] += ray_color(&scene, &camera.get_ray(u, v)); + } + } + + for i in 0..image.width { + buffer[i] = (colors[i] / image.samples_per_pixel as f64).as_color(); } Ok((row, buffer)) } +fn create_scene() -> Scene { + let mut scene = Scene::new(); + let sphere1 = Sphere::new(Vec3::new(0.0, 0.0, -1.0), 0.5, Vec3::new(0.0, 1.0, 0.0)); + let sphere2 = Sphere::new( + Vec3::new(0.0, -100.5, -1.0), + 100.0, + Vec3::new(0.0, 1.0, 0.0), + ); + scene.add(Box::new(sphere1)); + scene.add(Box::new(sphere2)); + scene +} + async fn run( rows_per_update: u32, aspect_ratio: f64, - screen_height: usize, + screen_width: usize, + samples: usize, ) -> Result<(), error::TracerError> { - let image = image::Image::new(aspect_ratio, screen_height); + let image = image::Image::new(aspect_ratio, screen_width, samples); let camera = camera::Camera::new(&image, 2.0, 1.0); + let scene = create_scene(); let mut screen_buffer: Vec = vec![0; image.width * image.height]; let mut window = Window::new( @@ -61,13 +96,18 @@ async fn run( // One future per row is a bit high. // Could do something less spammy. for h in 0..image.height { - futs.push(raytrace(camera.clone(), image.clone(), h)); + // TODO: Either clone all or lock em all. + futs.push(raytrace(scene.clone(), camera.clone(), image.clone(), h)); } + // TODO: use rayon + // Since it's cooperative multitasking this is not really helpful at the moment. + // You will get pretty much get the same result without the tokio asyncness. + // using rayon with threads is a different matter. let mut complete = false; while window.is_open() && !window.is_key_down(Key::Escape) { if !complete { - for _ in 1..rows_per_update { + for _ in 0..rows_per_update { select! { res = futs.select_next_some() => { let row_buffer = res.expect("Expected to get data"); @@ -95,7 +135,7 @@ async fn run( #[tokio::main] async fn main() { - if let Err(e) = run(50, 16.0 / 9.0, 1200).await { + if let Err(e) = run(100, 16.0 / 9.0, 1200, 100).await { eprintln!("{}", e); std::process::exit(e.into()) } -- cgit v1.2.3