More spheres, formatting

This commit is contained in:
Jonathan Flueren 2022-06-29 16:17:28 +02:00
parent 398b9c1c29
commit 745fafeaad
6 changed files with 133 additions and 124 deletions

View file

@ -9,7 +9,6 @@ pub struct Camera {
v: Vec3,
w: Vec3,
lens_radius: f64,
}
impl Camera {
@ -51,13 +50,12 @@ impl Camera {
}
pub fn get_ray(&self, u: f64, v: f64) -> Ray {
let rd = self.lens_radius * Vec3::random_in_unit_disk();
let offset = rd.x() * self.u + rd.y() * self.v;
return Ray::new(
self.origin + offset,
self.lower_left_corner + u * self.horizontal + v * self.vertical - self.origin - offset,
)
);
}
}

View file

@ -1,12 +1,4 @@
use super::{
Point3,
Vec3,
Color,
Ray,
Material,
Arc,
Metal
};
use super::{Arc, Color, Material, Metal, Point3, Ray, Vec3};
pub struct HitRecord {
pub p: Point3,

View file

@ -4,22 +4,22 @@ mod camera;
mod color;
mod hittable;
mod hittable_list;
mod material;
mod ray;
mod utility;
mod vec3;
mod material;
use camera::Camera;
use hittable::{HitRecord, Hittable, Sphere};
use hittable_list::HittableList;
use image::{Rgb, RgbImage};
use material::{Dielectric, Lambertian, Material, Metal};
use ray::Ray;
use rayon::prelude::*;
use std::env;
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
use vec3::{Color, Point3, Vec3};
use material::{Material, Lambertian, Metal, Dielectric};
fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color {
let mut rec = HitRecord::empty();
@ -31,7 +31,10 @@ fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color {
if world.hit(r, 0.001, f64::INFINITY, &mut rec) {
let mut scattered = Ray::new(Point3::null(), Vec3::null());
let mut attenuation = Color::null();
if rec.mat_ptr.scatter(r, &rec, &mut attenuation, &mut scattered) {
if rec
.mat_ptr
.scatter(r, &rec, &mut attenuation, &mut scattered)
{
return attenuation * ray_color(&scattered, world, depth - 1);
}
return Color::null();
@ -47,61 +50,62 @@ fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color {
fn random_world() -> HittableList {
let mut world = HittableList::new();
let material_ground = Arc::new(Lambertian::new(&Color::new(0.1, 0.1, 0.1)));
//let material_center = Arc::new(Lambertian::new(&Color::new(0.7, 0.1, 0.2)));
//let material_center = Arc::new(Dielectric::new(1.5));
//let material_blue = Arc::new(Lambertian::new(&Color::new(0.2, 0.1, 0.7)));
//let material_metal = Arc::new(Metal::new(&Color::new(0.8, 0.8, 0.8), 0.1));
//let material_metal_fuzz = Arc::new(Metal::new(&Color::new(0.8, 0.8, 0.8), 1.0));
//let material_mirror = Arc::new(Metal::new(&Color::new(0.8, 0.8, 0.8), 0.0));
//let material_dielectric = Arc::new(Dielectric::new(1.5));
//let material_light = Arc::new(Lambertian::new(&Color::new(2.0, 1.0, 0.0)));
let material_ground = Arc::new(Lambertian::new(&Color::new(0.01, 0.01, 0.01)));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(0.0, -1000.0, 0.0),
1000.0,
Point3::new(0.0, -50000.0, 0.0),
50000.0,
material_ground.clone(),
)));
(-6..5).into_iter().for_each(|a| {
(-6..5).into_iter().for_each(|b| {
let choose_mat = utility::random_f64();
let center = Point3::new(a as f64 + 0.9 * utility::random_f64(), 0.2, b as f64 + 0.9 * utility::random_f64());
let center = Point3::new(
1.5 * a as f64 + 1.3 * utility::random_f64(),
0.2,
1.5 * b as f64 + 1.3 * utility::random_f64(),
);
if (center - Point3::new(4.0, 0.2, 0.0)).length() > 0.9 {
if choose_mat < 0.8 { // diffuse
let sphere_material = Arc::new(Lambertian::new(&(Color::random_f64() * Color::random_f64())));
if choose_mat < 0.8 {
// diffuse
let sphere_material = Arc::new(Lambertian::new(
&(Color::random_f64() * Color::random_f64()),
));
world.add(Box::<Sphere>::new(Sphere::new(
center,
0.2,
sphere_material.clone()
sphere_material.clone(),
)));
} else if choose_mat < 0.95 { // metal
let sphere_material = Arc::new(Metal::new(&Color::random_rng(0.5, 1.0), utility::random_rng(0.0, 0.5)));
} else if choose_mat < 0.95 {
// metal
let sphere_material = Arc::new(Metal::new(
&Color::random_rng(0.5, 1.0),
utility::random_rng(0.0, 0.5),
));
world.add(Box::<Sphere>::new(Sphere::new(
center,
0.2,
sphere_material.clone()
sphere_material.clone(),
)));
} else { // glass
} else {
// glass
let sphere_material = Arc::new(Dielectric::new(1.5));
world.add(Box::<Sphere>::new(Sphere::new(
center,
0.2,
sphere_material.clone()
sphere_material.clone(),
)));
}
}
});
});
let material1 = Arc::new(Dielectric::new(1.5));
let material3 = Arc::new(Metal::new(&Color::new(0.7, 0.6, 0.5), 0.0));
let material2 = Arc::new(Lambertian::new(&Color::new(0.4, 0.2, 0.1)));
let material3 = Arc::new(Metal::new(&Color::new(0.7, 0.6, 0.5), 0.0));
let material4 = Arc::new(Dielectric::new(2.0));
let material5 = Arc::new(Metal::new(&Color::new(0.9, 0.9, 0.7), 0.0));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(0.0, 1.0, 0.0),
@ -121,41 +125,17 @@ fn random_world() -> HittableList {
material3.clone(),
)));
/*
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(-2.0*r, 0.1, -2.0),
r,
material_dielectric.clone(),
Point3::new(-2.0, 2.0, -5.0),
2.0,
material4.clone(),
)));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(r, 0.0, -1.0),
r,
material_dielectric.clone(),
)));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(-1.5, 1.3, -1.7),
0.4,
material_mirror.clone(),
)));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(-0.5, 0.5, 1.0),
0.4,
material_blue.clone(),
)));
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(0.5, 1.0, 0.3),
0.3,
material_light.clone(),
)));
*/
/*
for i in -15..15 {
for j in -15..15 {
world.add(Box::<Sphere>::new(Sphere::new(Point3::new(j as f64/5.0 as f64, i as f64/5.0 as f64, -1.5), 0.08)));
}
}
*/
world.add(Box::<Sphere>::new(Sphere::new(
Point3::new(-3.6, 2.0, -2.0),
0.6,
material5.clone(),
)));
return world;
}
@ -166,23 +146,31 @@ fn main() {
// Image
let aspect_ratio = 16.0 / 9.0;
let image_width = 1920;
let image_width = 1000;
let image_height = (image_width as f64 / aspect_ratio) as u32;
let samples_per_pixel = 100_u32;
let max_depth = 50;
let vfov = 20.0;
let lookfrom = Point3::new(10.0, 10.0, 13.0);
let vfov = 25.0;
let lookfrom = Point3::new(10.0, 4.0, 13.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 = 15.0;
let dist_to_focus = 17.0;
let aperture = 0.1;
// World
let world = random_world();
// Camera
let cam = Camera::new(lookfrom, lookat, vup, vfov, aspect_ratio, aperture, dist_to_focus);
let cam = Camera::new(
lookfrom,
lookat,
vup,
vfov,
aspect_ratio,
aperture,
dist_to_focus,
);
// Render
let args: Vec<String> = env::args().collect();

View file

@ -1,10 +1,4 @@
use super::{
Ray,
HitRecord,
Color,
Vec3,
utility,
};
use super::{utility, Color, HitRecord, Ray, Vec3};
pub struct Lambertian {
albedo: Color,
@ -23,21 +17,30 @@ pub struct Dielectric {
ir: f64,
}
pub trait Material: Sync + Send {
fn scatter(&self,r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool;
fn scatter(
&self,
r_in: &Ray,
rec: &HitRecord,
attenuation: &mut Color,
scattered: &mut Ray,
) -> bool;
}
impl Lambertian {
pub fn new(a: &Color) -> Self {
Lambertian {
albedo: a.clone(),
}
Lambertian { albedo: a.clone() }
}
}
impl Material for Lambertian {
fn scatter(&self, _r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
fn scatter(
&self,
_r_in: &Ray,
rec: &HitRecord,
attenuation: &mut Color,
scattered: &mut Ray,
) -> bool {
let mut scatter_direction = rec.normal + Vec3::random_unit_vector();
if scatter_direction.near_zero() {
@ -60,7 +63,13 @@ impl Metal {
}
impl Material for Metal {
fn scatter(&self, r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
fn scatter(
&self,
r_in: &Ray,
rec: &HitRecord,
attenuation: &mut Color,
scattered: &mut Ray,
) -> bool {
let reflected = Vec3::reflect(&Vec3::unit_vector(r_in.direction()), &rec.normal);
*scattered = Ray::new(rec.p, reflected + self.fuzz * Vec3::random_in_unit_sphere());
@ -72,22 +81,27 @@ impl Material for Metal {
impl Mirror {
pub fn new(a: &Color) -> Self {
Mirror {
albedo: *a,
}
Mirror { albedo: *a }
}
}
impl Material for Mirror {
fn scatter(&self, r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
if utility::random_f64() > 0.8 { // Reflektiert
fn scatter(
&self,
r_in: &Ray,
rec: &HitRecord,
attenuation: &mut Color,
scattered: &mut Ray,
) -> bool {
if utility::random_f64() > 0.8 {
// Reflektiert
let reflected = Vec3::reflect(&Vec3::unit_vector(r_in.direction()), &rec.normal);
*scattered = Ray::new(rec.p, reflected);
*attenuation = self.albedo.clone();
return Vec3::dot(scattered.direction(), rec.normal) > 0.0;
} else { // Geht geradeaus durch
} else {
// Geht geradeaus durch
let reflected = r_in.direction().clone();
*scattered = Ray::new(rec.p, reflected);
@ -112,9 +126,19 @@ impl Dielectric {
}
impl Material for Dielectric {
fn scatter(&self, r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
fn scatter(
&self,
r_in: &Ray,
rec: &HitRecord,
attenuation: &mut Color,
scattered: &mut Ray,
) -> bool {
*attenuation = Color::new(1.0, 1.0, 1.0);
let refraction_ratio = if rec.front_face { 1.0 / self.ir } else { self.ir };
let refraction_ratio = if rec.front_face {
1.0 / self.ir
} else {
self.ir
};
let unit_direction = Vec3::unit_vector(r_in.direction());
let cos_theta = Vec3::dot(-1.0 * unit_direction, rec.normal).min(1.0);
@ -122,7 +146,10 @@ impl Material for Dielectric {
let mut direction = Vec3::refract(&unit_direction, &rec.normal, refraction_ratio); // can reflect
if refraction_ratio * sin_theta > 1.0 || Dielectric::reflectance(cos_theta, refraction_ratio) > utility::random_f64() { // must reflect
if refraction_ratio * sin_theta > 1.0
|| Dielectric::reflectance(cos_theta, refraction_ratio) > utility::random_f64()
{
// must reflect
direction = Vec3::reflect(&unit_direction, &rec.normal);
}

View file

@ -90,7 +90,11 @@ impl Vec3 {
pub fn random_in_unit_disk() -> Self {
loop {
let p = Vec3::new(utility::random_rng(-1.0, 1.0), utility::random_rng(-1.0, 1.0), 0.0);
let p = Vec3::new(
utility::random_rng(-1.0, 1.0),
utility::random_rng(-1.0, 1.0),
0.0,
);
if p.length_squared() >= 1.0 {
continue;
}