Write output to file

This commit is contained in:
Max Nuding 2022-07-02 15:42:04 +02:00
parent 388c48d236
commit 2903c9b0b9
Signed by: phlaym
GPG Key ID: 0AAD39863E09DC48
3 changed files with 62 additions and 12 deletions

View File

@ -1,5 +1,6 @@
use crate::camera::Camera; use crate::camera::Camera;
use crate::hittable::{Hittable, Sphere}; use crate::hittable::{Hittable, Sphere};
use crate::output::{Output, P3};
use crate::ray::Ray; use crate::ray::Ray;
use crate::vec3::{Color, Point3, Vec3}; use crate::vec3::{Color, Point3, Vec3};
use rand::distributions::{Distribution, Uniform}; use rand::distributions::{Distribution, Uniform};
@ -10,6 +11,7 @@ mod ray;
mod hittable; mod hittable;
mod material; mod material;
mod camera; mod camera;
mod output;
fn random_scene() -> Vec<Box<dyn Hittable>> { fn random_scene() -> Vec<Box<dyn Hittable>> {
let mut world:Vec<Box<dyn Hittable>> = Vec::new(); let mut world:Vec<Box<dyn Hittable>> = Vec::new();
@ -52,15 +54,35 @@ fn random_scene() -> Vec<Box<dyn Hittable>> {
world.push(sphere); world.push(sphere);
} }
} }
let material1 = Material::Dielectric(Dielectric::new(1.5));
world.push(Box::new(Sphere {
center: Point3::new(0.0, 1.0, 0.0),
radius: 1.0,
material: material1
}));
let material2 = Material::Lambertian(Lambertian::new(Color::new(0.4, 0.2, 0.1)));
world.push(Box::new(Sphere {
center: Point3::new(-4.0, 1.0, 0.0),
radius: 1.0,
material: material2
}));
let material3 = Material::Metal(Metal::new(Color::new(0.7, 0.6, 0.5), 0.0));
world.push(Box::new(Sphere {
center: Point3::new(4.0, 1.0, 0.0),
radius: 1.0,
material: material3
}));
world world
} }
fn main() { fn main() {
// Image // Image
const ASPECT_RATIO: f64 = 3.0 / 2.0; const ASPECT_RATIO: f64 = 3.0 / 2.0;
const IMAGE_WIDTH: i32 = 1200; const IMAGE_WIDTH: usize = 1200;
const IMAGE_HEIGHT: i32 = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as i32; const IMAGE_HEIGHT: usize = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as usize;
const SAMPLES_PER_PIXEL: i32 = 10; const SAMPLES_PER_PIXEL: i32 = 100;
const MAX_DEPTH: i32 = 50; const MAX_DEPTH: i32 = 50;
let look_from = Point3::new(13.0, 2.0, 3.0); let look_from = Point3::new(13.0, 2.0, 3.0);
@ -79,26 +101,27 @@ fn main() {
// World // World
let world= random_scene(); let world= random_scene();
println!("P3\n{} {}\n255", IMAGE_WIDTH, IMAGE_HEIGHT); //println!("P3\n{} {}\n255", IMAGE_WIDTH, IMAGE_HEIGHT);
let between = Uniform::from(0.0..1.0); let between = Uniform::from(0.0..1.0);
let mut pixels = Vec::<u8>::new();
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
for j in (0..IMAGE_HEIGHT).rev() { for j in (0..IMAGE_HEIGHT).rev() {
eprint!("\rScanlines remaining: {} ", j); eprint!("\rScanlines remaining: {} ", j);
for i in 0..IMAGE_WIDTH { for i in 0..IMAGE_WIDTH {
let mut color = Color::default(); let mut color = Color::default();
for s in 0..SAMPLES_PER_PIXEL { (0..SAMPLES_PER_PIXEL).for_each(|_s| {
let random_number = between.sample(&mut rng); let random_number = between.sample(&mut rng);
let u = (i as f64 + random_number) / (IMAGE_WIDTH - 1) as f64; let u = (i as f64 + random_number) / (IMAGE_WIDTH - 1) as f64;
let v = (j as f64 + random_number) / (IMAGE_HEIGHT - 1) as f64; let v = (j as f64 + random_number) / (IMAGE_HEIGHT - 1) as f64;
let ray = cam.get_ray(u, v); let ray = cam.get_ray(u, v);
if i == 200 && (j == 112 || j == 113) {
let tt = 0;
}
color += ray.pixel_color(&world, MAX_DEPTH); color += ray.pixel_color(&world, MAX_DEPTH);
} });
color.write_color(SAMPLES_PER_PIXEL); pixels.append(&mut color.into_bytes(SAMPLES_PER_PIXEL));
//color.write_color(SAMPLES_PER_PIXEL);
} }
} }
P3::write("i.ppm", &pixels, IMAGE_WIDTH, IMAGE_HEIGHT).expect("Error writing image: {}");
eprintln!("\nDone"); eprintln!("\nDone");
} }

19
src/output.rs Normal file
View File

@ -0,0 +1,19 @@
use std::{fs::File, io::{Error, Write}};
pub trait Output {
fn write(filename: &str, pixels: &Vec<u8>, width: usize, height: usize) -> Result<File, Error>;
}
pub struct P3 {}
impl Output for P3 {
fn write(filename: &str, pixels: &Vec<u8>, width: usize, height: usize) -> Result<File, Error> {
let mut file = File::create(filename)?;
file.write(format!("P3\n{} {}\n255\n", width, height).as_bytes())?;
let lines: Result<Vec<usize>, Error> = pixels
.chunks(3)
.map(|chunk| format!("{} {} {}\n", chunk[0], chunk[1], chunk[2]))
.map(|line| file.write(line.as_bytes()))
.collect();
lines.map(|_v| file)
}
}

View File

@ -105,12 +105,12 @@ fn test_refract() {
let n = Point3::new(-1.0, 0.0, 0.0); let n = Point3::new(-1.0, 0.0, 0.0);
let etai_over_etat = 1.0; let etai_over_etat = 1.0;
let expected = Point3::new(0.0, 1.0, 0.0); let expected = Point3::new(0.0, 1.0, 0.0);
let actual = uv.refract_orig( &n, etai_over_etat); let actual = uv.refract( &n, etai_over_etat);
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }
impl Color { impl Color {
pub fn write_color(self: Color, samples_per_pixel: i32) { fn tone_map(self: &Color, samples_per_pixel: i32) -> (f64, f64, f64) {
let scale = 1.0 / samples_per_pixel as f64; let scale = 1.0 / samples_per_pixel as f64;
let r = f64::sqrt(scale * self.x); let r = f64::sqrt(scale * self.x);
let g = f64::sqrt(scale * self.y); let g = f64::sqrt(scale * self.y);
@ -118,8 +118,16 @@ impl Color {
let r = 256.0 * f64::clamp(r, 0.0, 0.999); let r = 256.0 * f64::clamp(r, 0.0, 0.999);
let g = 256.0 * f64::clamp(g, 0.0, 0.999); let g = 256.0 * f64::clamp(g, 0.0, 0.999);
let b = 256.0 * f64::clamp(b, 0.0, 0.999); let b = 256.0 * f64::clamp(b, 0.0, 0.999);
(r, g, b)
}
pub fn write_color(self: &Color, samples_per_pixel: i32) {
let (r, g, b) = self.tone_map(samples_per_pixel);
println!("{} {} {}", r as i32, g as i32, b as i32); println!("{} {} {}", r as i32, g as i32, b as i32);
} }
pub fn into_bytes(self: &Color, samples_per_pixel: i32) -> Vec<u8> {
let (r, g, b) = self.tone_map(samples_per_pixel);
vec![r as u8, g as u8, b as u8]
}
} }
impl Default for Vec3 { impl Default for Vec3 {