diff --git a/.gitignore b/.gitignore index bb580b5..2950a6c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ /target -*.ppm -*.jpg -*.png +/*.ppm +/*.jpg +/*.png flamegraph.svg perf.data* diff --git a/README.md b/README.md index fa93836..b85e500 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,13 @@ # Renderer - Grafik-AG +Following [Raytracing In One Weekend](https://raytracing.github.io/books/RayTracingInOneWeekend.html). + +Rendered images in `images/`. + +![RaytracingInOneWeekend](images/RayTracingInOneWeekend2.png) + +![Suzanne Rainbow](images/suzanne_rainbow.png) + *** ### Performance analysis with Flamegraph https://github.com/flamegraph-rs/flamegraph diff --git a/images/Baum_without_Antialiasing.png b/images/Baum_without_Antialiasing.png new file mode 100644 index 0000000..0978460 Binary files /dev/null and b/images/Baum_without_Antialiasing.png differ diff --git a/images/RayTracingInOneWeekend1.jpg b/images/RayTracingInOneWeekend1.jpg new file mode 100644 index 0000000..6298910 Binary files /dev/null and b/images/RayTracingInOneWeekend1.jpg differ diff --git a/images/RayTracingInOneWeekend2.png b/images/RayTracingInOneWeekend2.png new file mode 100644 index 0000000..5ae4c53 Binary files /dev/null and b/images/RayTracingInOneWeekend2.png differ diff --git a/images/RayTracingInOneWeekend3.png b/images/RayTracingInOneWeekend3.png new file mode 100644 index 0000000..9d4d150 Binary files /dev/null and b/images/RayTracingInOneWeekend3.png differ diff --git a/images/RayTracingInOneWeekend4.png b/images/RayTracingInOneWeekend4.png new file mode 100644 index 0000000..0394ead Binary files /dev/null and b/images/RayTracingInOneWeekend4.png differ diff --git a/images/cat.png b/images/cat.png new file mode 100644 index 0000000..173ec4a Binary files /dev/null and b/images/cat.png differ diff --git a/images/suzanne_rainbow.png b/images/suzanne_rainbow.png new file mode 100644 index 0000000..438b609 Binary files /dev/null and b/images/suzanne_rainbow.png differ diff --git a/images/suzanne_rainbow2.png b/images/suzanne_rainbow2.png new file mode 100644 index 0000000..6f89696 Binary files /dev/null and b/images/suzanne_rainbow2.png differ diff --git a/src/color.rs b/src/color.rs index 296eff6..8ed9059 100644 --- a/src/color.rs +++ b/src/color.rs @@ -5,10 +5,10 @@ pub fn put_color(img: &mut RgbImage, pixel_color: &Color, x: u32, y: u32, sample let mut g = pixel_color.y(); let mut b = pixel_color.z(); - let scale = 1.0 / samples_per_pixel as f64; - r = (scale * r).sqrt(); - g = (scale * g).sqrt(); - b = (scale * b).sqrt(); + //let scale = 1.0 / samples_per_pixel as f64; + //r = r/samples_per_pixel as f64; //(scale * r).sqrt(); + //g = g/samples_per_pixel as f64; //(scale * g).sqrt(); + //b = b/samples_per_pixel as f64; //(scale * b).sqrt(); img.put_pixel( x, diff --git a/src/main.rs b/src/main.rs index 3cc845e..6c5f499 100644 --- a/src/main.rs +++ b/src/main.rs @@ -292,33 +292,33 @@ Current world view: / z \ x */ - fn main() { // File let mut default_file = "image.ppm"; // Image - let aspect_ratio = 10.0/7.5; //16.0 / 9.0; - let image_width = 1000; + let aspect_ratio = 10.0 / 7.5; //16.0 / 9.0; + let image_width = 400; let image_height = (image_width as f64 / aspect_ratio) as u32; - let samples_per_pixel = 100_u32; + let samples_per_pixel = 50_u32; let max_depth = 50; + let antialiasing_threshold = 0.3; // at what diff between two colors will a pixel be antialiased let vfov = 40.0; let lookfrom = Point3::new(2.0, 0.8, 3.0); let lookat = Point3::new(0.0, 0.0, 0.0); let vup = Vec3::new(0.0, 1.0, 0.0); let dist_to_focus = 3.0; - let aperture = 0.1; + let aperture = 0.0; // disable depth of field // limit rayon multithreading thread count - let thread_count = 6; // if 0, for each logical cpu core a thread wil be created + let thread_count = 4; // if 0, for each logical cpu core a thread wil be created if thread_count > 0 { env::set_var("RAYON_NUM_THREADS", thread_count.to_string()); } // World - eprintln!("[1/3] Loading meshes from file..."); + eprintln!("[1/4] Loading meshes from file..."); let world = from_obj("obj/suzanne.obj"); // let world = random_world(); @@ -339,7 +339,7 @@ fn main() { default_file = &args[1]; } - eprintln!("[2/3] Gerenating image..."); + eprintln!("[2/4] Generating image..."); let bar = ProgressBar::new(image_height as u64); let mut image = RgbImage::new(image_width, image_height); @@ -353,20 +353,14 @@ fn main() { let mut colors = Vec::new(); for i in 0..image_width { - let mut pixel_color = ray_color( + let pixel_color = ray_color( &cam.get_ray( i as f64 / (image_width - 1) as f64, j as f64 / (image_height - 1) as f64, ), &world, max_depth, - ); // first ray not antialiased to disable antialiasing on value 1 - for _ in 1..samples_per_pixel { - let u = (i as f64 + utility::random_f64()) / (image_width - 1) as f64; - let v = (j as f64 + utility::random_f64()) / (image_height - 1) as f64; - let r = cam.get_ray(u, v); - pixel_color += ray_color(&r, &world, max_depth); - } + ); colors.push(pixel_color); } return colors; @@ -374,15 +368,99 @@ fn main() { .collect(); bar.finish_and_clear(); - eprintln!("[3/3] Exporting image to disk..."); + eprintln!("[3/4] Antialiasing image..."); + let mut antialiasing: Vec> = Vec::new(); + let mut antialiasing_counter = 0; + let mut antialiasing_col_counter = 0; + let mut antialiases_per_line: Vec = Vec::new(); + (0..image_height).into_iter().for_each(|j| { + antialiasing.push(Vec::new()); + (0..image_width).into_iter().for_each(|i| { + if j != 0 + && Color::diff( + &color_lines[(j - 1) as usize][i as usize], + &color_lines[j as usize][i as usize], + ) >= antialiasing_threshold + { + antialiasing[j as usize].push(true); + antialiasing_col_counter += 1; + } else if j != image_height - 1 + && Color::diff( + &color_lines[(j + 1) as usize][i as usize], + &color_lines[j as usize][i as usize], + ) >= antialiasing_threshold + { + antialiasing[j as usize].push(true); + antialiasing_col_counter += 1; + } else if i != 0 + && Color::diff( + &color_lines[j as usize][(i - 1) as usize], + &color_lines[j as usize][i as usize], + ) >= antialiasing_threshold + { + antialiasing[j as usize].push(true); + antialiasing_col_counter += 1; + } else if i != image_width - 1 + && Color::diff( + &color_lines[j as usize][(i + 1) as usize], + &color_lines[j as usize][i as usize], + ) >= antialiasing_threshold + { + antialiasing[j as usize].push(true); + antialiasing_col_counter += 1; + } + if antialiasing[j as usize].len() < (i + 1) as usize { + antialiasing[j as usize].push(false); + } + }); + antialiases_per_line.push(antialiasing_col_counter); + antialiasing_counter += antialiasing_col_counter; + antialiasing_col_counter = 0; + }); + + let bar = ProgressBar::new(antialiasing_counter as u64); + let color_lines_antialiased: Vec<_> = (0..image_height) + .into_par_iter() // threadded/parallel variant + //.into_iter() // iterative variant + .map(|j| { + let mut colors = Vec::new(); + for i in 0..image_width { + if samples_per_pixel > 0 && antialiasing[j as usize][i as usize] { + let mut pixel_color = Color::null(); + for _ in 0..samples_per_pixel { + let u = (i as f64 + utility::random_f64()) / (image_width - 1) as f64; + let v = (j as f64 + utility::random_f64()) / (image_height - 1) as f64; + let r = cam.get_ray(u, v); + dbg!(ray_color(&r, &world, max_depth)); + pixel_color += ray_color(&r, &world, max_depth); + } + // Correct antialiasing gamma + pixel_color = Color::new( + pixel_color.x() / samples_per_pixel as f64, + pixel_color.y() / samples_per_pixel as f64, + pixel_color.z() / samples_per_pixel as f64, + ); + println!("x: {}, y: {}, z: {}", pixel_color.x(), pixel_color.y(), pixel_color.z()); + colors.push(pixel_color); + } else { + colors.push(color_lines[j as usize][i as usize]); + } + } + bar.inc(antialiases_per_line[j as usize]); + return colors; + }) + .collect(); + bar.finish_and_clear(); + + eprintln!("[4/4] Exporting image to disk..."); (0..image_height).into_iter().rev().for_each(|j| { (0..image_width).into_iter().for_each(|i| { color::put_color( &mut image, - &color_lines[(image_height - j - 1) as usize][i as usize], + &color_lines_antialiased[(image_height - j - 1) as usize][i as usize], i, image_height - j - 1, - samples_per_pixel, + 1, ); }) }); diff --git a/src/material.rs b/src/material.rs index a8663d8..2b90b45 100644 --- a/src/material.rs +++ b/src/material.rs @@ -17,9 +17,7 @@ pub struct Dielectric { ir: f64, } -pub struct Rainbow { - -} +pub struct Rainbow {} pub trait Material: Sync + Send { fn scatter( @@ -183,12 +181,13 @@ impl Material for Rainbow { } *scattered = Ray::new(rec.p, scatter_direction); - let color = 0.5*Color::new( - rec.normal.x()+1.0, - rec.normal.y()+1.0, - rec.normal.z()+1.0 - ); + let color = 0.5 + * Color::new( + rec.normal.x() + 1.0, + rec.normal.y() + 1.0, + rec.normal.z() + 1.0, + ); *attenuation = color; return true; } -} \ No newline at end of file +} diff --git a/src/vec3.rs b/src/vec3.rs index 22b3a7d..b76ec27 100644 --- a/src/vec3.rs +++ b/src/vec3.rs @@ -30,6 +30,10 @@ impl Vec3 { self.e[0] * self.e[0] + self.e[1] * self.e[1] + self.e[2] * self.e[2] } + pub fn diff(a: &Self, b: &Self) -> f64 { + (a.x() - b.x()).abs() + (a.y() - b.y()).abs() + (a.z() - b.z()).abs() + } + pub fn cross(a: Vec3, b: Vec3) -> Vec3 { Vec3::new( a.y() * b.z() - a.z() * b.y(),