Add images
6
.gitignore
vendored
|
@ -1,6 +1,6 @@
|
||||||
/target
|
/target
|
||||||
*.ppm
|
/*.ppm
|
||||||
*.jpg
|
/*.jpg
|
||||||
*.png
|
/*.png
|
||||||
flamegraph.svg
|
flamegraph.svg
|
||||||
perf.data*
|
perf.data*
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
# Renderer - Grafik-AG
|
# 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
|
### Performance analysis with Flamegraph
|
||||||
https://github.com/flamegraph-rs/flamegraph
|
https://github.com/flamegraph-rs/flamegraph
|
||||||
|
|
BIN
images/Baum_without_Antialiasing.png
Normal file
After Width: | Height: | Size: 738 KiB |
BIN
images/RayTracingInOneWeekend1.jpg
Normal file
After Width: | Height: | Size: 256 KiB |
BIN
images/RayTracingInOneWeekend2.png
Normal file
After Width: | Height: | Size: 4 MiB |
BIN
images/RayTracingInOneWeekend3.png
Normal file
After Width: | Height: | Size: 2.1 MiB |
BIN
images/RayTracingInOneWeekend4.png
Normal file
After Width: | Height: | Size: 578 KiB |
BIN
images/cat.png
Normal file
After Width: | Height: | Size: 674 KiB |
BIN
images/suzanne_rainbow.png
Normal file
After Width: | Height: | Size: 454 KiB |
BIN
images/suzanne_rainbow2.png
Normal file
After Width: | Height: | Size: 520 KiB |
|
@ -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 g = pixel_color.y();
|
||||||
let mut b = pixel_color.z();
|
let mut b = pixel_color.z();
|
||||||
|
|
||||||
let scale = 1.0 / samples_per_pixel as f64;
|
//let scale = 1.0 / samples_per_pixel as f64;
|
||||||
r = (scale * r).sqrt();
|
//r = r/samples_per_pixel as f64; //(scale * r).sqrt();
|
||||||
g = (scale * g).sqrt();
|
//g = g/samples_per_pixel as f64; //(scale * g).sqrt();
|
||||||
b = (scale * b).sqrt();
|
//b = b/samples_per_pixel as f64; //(scale * b).sqrt();
|
||||||
|
|
||||||
img.put_pixel(
|
img.put_pixel(
|
||||||
x,
|
x,
|
||||||
|
|
116
src/main.rs
|
@ -292,33 +292,33 @@ Current world view:
|
||||||
/ z \ x
|
/ z \ x
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// File
|
// File
|
||||||
let mut default_file = "image.ppm";
|
let mut default_file = "image.ppm";
|
||||||
|
|
||||||
// Image
|
// Image
|
||||||
let aspect_ratio = 10.0/7.5; //16.0 / 9.0;
|
let aspect_ratio = 10.0 / 7.5; //16.0 / 9.0;
|
||||||
let image_width = 1000;
|
let image_width = 400;
|
||||||
let image_height = (image_width as f64 / aspect_ratio) as u32;
|
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 max_depth = 50;
|
||||||
|
let antialiasing_threshold = 0.3; // at what diff between two colors will a pixel be antialiased
|
||||||
|
|
||||||
let vfov = 40.0;
|
let vfov = 40.0;
|
||||||
let lookfrom = Point3::new(2.0, 0.8, 3.0);
|
let lookfrom = Point3::new(2.0, 0.8, 3.0);
|
||||||
let lookat = Point3::new(0.0, 0.0, 0.0);
|
let lookat = Point3::new(0.0, 0.0, 0.0);
|
||||||
let vup = Vec3::new(0.0, 1.0, 0.0);
|
let vup = Vec3::new(0.0, 1.0, 0.0);
|
||||||
let dist_to_focus = 3.0;
|
let dist_to_focus = 3.0;
|
||||||
let aperture = 0.1;
|
let aperture = 0.0; // disable depth of field
|
||||||
|
|
||||||
// limit rayon multithreading thread count
|
// 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 {
|
if thread_count > 0 {
|
||||||
env::set_var("RAYON_NUM_THREADS", thread_count.to_string());
|
env::set_var("RAYON_NUM_THREADS", thread_count.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// World
|
// World
|
||||||
eprintln!("[1/3] Loading meshes from file...");
|
eprintln!("[1/4] Loading meshes from file...");
|
||||||
let world = from_obj("obj/suzanne.obj");
|
let world = from_obj("obj/suzanne.obj");
|
||||||
// let world = random_world();
|
// let world = random_world();
|
||||||
|
|
||||||
|
@ -339,7 +339,7 @@ fn main() {
|
||||||
default_file = &args[1];
|
default_file = &args[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
eprintln!("[2/3] Gerenating image...");
|
eprintln!("[2/4] Generating image...");
|
||||||
let bar = ProgressBar::new(image_height as u64);
|
let bar = ProgressBar::new(image_height as u64);
|
||||||
|
|
||||||
let mut image = RgbImage::new(image_width, image_height);
|
let mut image = RgbImage::new(image_width, image_height);
|
||||||
|
@ -353,20 +353,14 @@ fn main() {
|
||||||
|
|
||||||
let mut colors = Vec::new();
|
let mut colors = Vec::new();
|
||||||
for i in 0..image_width {
|
for i in 0..image_width {
|
||||||
let mut pixel_color = ray_color(
|
let pixel_color = ray_color(
|
||||||
&cam.get_ray(
|
&cam.get_ray(
|
||||||
i as f64 / (image_width - 1) as f64,
|
i as f64 / (image_width - 1) as f64,
|
||||||
j as f64 / (image_height - 1) as f64,
|
j as f64 / (image_height - 1) as f64,
|
||||||
),
|
),
|
||||||
&world,
|
&world,
|
||||||
max_depth,
|
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);
|
colors.push(pixel_color);
|
||||||
}
|
}
|
||||||
return colors;
|
return colors;
|
||||||
|
@ -374,15 +368,99 @@ fn main() {
|
||||||
.collect();
|
.collect();
|
||||||
bar.finish_and_clear();
|
bar.finish_and_clear();
|
||||||
|
|
||||||
eprintln!("[3/3] Exporting image to disk...");
|
eprintln!("[3/4] Antialiasing image...");
|
||||||
|
let mut antialiasing: Vec<Vec<bool>> = Vec::new();
|
||||||
|
let mut antialiasing_counter = 0;
|
||||||
|
let mut antialiasing_col_counter = 0;
|
||||||
|
let mut antialiases_per_line: Vec<u64> = 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_height).into_iter().rev().for_each(|j| {
|
||||||
(0..image_width).into_iter().for_each(|i| {
|
(0..image_width).into_iter().for_each(|i| {
|
||||||
color::put_color(
|
color::put_color(
|
||||||
&mut image,
|
&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,
|
i,
|
||||||
image_height - j - 1,
|
image_height - j - 1,
|
||||||
samples_per_pixel,
|
1,
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,9 +17,7 @@ pub struct Dielectric {
|
||||||
ir: f64,
|
ir: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Rainbow {
|
pub struct Rainbow {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Material: Sync + Send {
|
pub trait Material: Sync + Send {
|
||||||
fn scatter(
|
fn scatter(
|
||||||
|
@ -183,11 +181,12 @@ impl Material for Rainbow {
|
||||||
}
|
}
|
||||||
|
|
||||||
*scattered = Ray::new(rec.p, scatter_direction);
|
*scattered = Ray::new(rec.p, scatter_direction);
|
||||||
let color = 0.5*Color::new(
|
let color = 0.5
|
||||||
rec.normal.x()+1.0,
|
* Color::new(
|
||||||
rec.normal.y()+1.0,
|
rec.normal.x() + 1.0,
|
||||||
rec.normal.z()+1.0
|
rec.normal.y() + 1.0,
|
||||||
);
|
rec.normal.z() + 1.0,
|
||||||
|
);
|
||||||
*attenuation = color;
|
*attenuation = color;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,10 @@ impl Vec3 {
|
||||||
self.e[0] * self.e[0] + self.e[1] * self.e[1] + self.e[2] * self.e[2]
|
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 {
|
pub fn cross(a: Vec3, b: Vec3) -> Vec3 {
|
||||||
Vec3::new(
|
Vec3::new(
|
||||||
a.y() * b.z() - a.z() * b.y(),
|
a.y() * b.z() - a.z() * b.y(),
|
||||||
|
|